lokuma-cli 1.3.2 → 1.3.4
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/assets/design.py +198 -0
- package/dist/index.js +67 -138
- package/package.json +1 -1
package/assets/design.py
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Lokuma Design — Cloud Client
|
|
5
|
+
|
|
6
|
+
Just describe what you're building. Lokuma figures out the rest.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python design.py "<describe your product or design need>"
|
|
10
|
+
python design.py "<describe your product or design need>" -p "Project Name"
|
|
11
|
+
python design.py "<describe your product or design need>" -f json
|
|
12
|
+
python design.py "<describe your product or design need>" -f markdown
|
|
13
|
+
|
|
14
|
+
Examples:
|
|
15
|
+
python design.py "A meditation app for stressed professionals. Calm, premium, organic."
|
|
16
|
+
python design.py "A landing page for an AI sales SaaS. Sharp, fast, conversion-focused." -p "Closer"
|
|
17
|
+
python design.py "What color palette fits a luxury skincare brand?" -f json
|
|
18
|
+
python design.py "Best font pairing for a fintech dashboard" -f markdown
|
|
19
|
+
|
|
20
|
+
Setup:
|
|
21
|
+
export LOKUMA_API_KEY=lokuma_your_key_here
|
|
22
|
+
Get your key at https://lokuma.ai
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import argparse
|
|
26
|
+
import json
|
|
27
|
+
import os
|
|
28
|
+
import sys
|
|
29
|
+
import io
|
|
30
|
+
import urllib.request
|
|
31
|
+
import urllib.error
|
|
32
|
+
from typing import Optional
|
|
33
|
+
|
|
34
|
+
# Force UTF-8 output on Windows
|
|
35
|
+
if sys.stdout.encoding and sys.stdout.encoding.lower() != "utf-8":
|
|
36
|
+
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
|
|
37
|
+
if sys.stderr.encoding and sys.stderr.encoding.lower() != "utf-8":
|
|
38
|
+
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# ─────────────────────────────────────────────
|
|
42
|
+
# Config
|
|
43
|
+
# ─────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
API_BASE = os.environ.get("LOKUMA_API_URL", "https://api.lokuma.ai").rstrip("/")
|
|
46
|
+
API_VERSION = "v1"
|
|
47
|
+
_BASE = f"{API_BASE}/{API_VERSION}"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _get_api_key() -> str:
|
|
51
|
+
key = os.environ.get("LOKUMA_API_KEY", "").strip()
|
|
52
|
+
if not key:
|
|
53
|
+
print(
|
|
54
|
+
"Error: LOKUMA_API_KEY is not set.\n"
|
|
55
|
+
"Set it with: export LOKUMA_API_KEY=lokuma_your_key_here\n"
|
|
56
|
+
"Get your key at https://lokuma.ai",
|
|
57
|
+
file=sys.stderr,
|
|
58
|
+
)
|
|
59
|
+
sys.exit(1)
|
|
60
|
+
return key
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# ─────────────────────────────────────────────
|
|
64
|
+
# HTTP client (stdlib only, zero deps)
|
|
65
|
+
# ─────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
def _post(endpoint: str, payload: dict) -> dict:
|
|
68
|
+
api_key = _get_api_key()
|
|
69
|
+
url = f"{_BASE}/{endpoint}"
|
|
70
|
+
data = json.dumps(payload, ensure_ascii=False).encode("utf-8")
|
|
71
|
+
|
|
72
|
+
req = urllib.request.Request(
|
|
73
|
+
url,
|
|
74
|
+
data=data,
|
|
75
|
+
headers={
|
|
76
|
+
"Content-Type": "application/json",
|
|
77
|
+
"X-API-Key": api_key,
|
|
78
|
+
"User-Agent": "lokuma-skill/2.0",
|
|
79
|
+
},
|
|
80
|
+
method="POST",
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
with urllib.request.urlopen(req, timeout=60) as resp:
|
|
85
|
+
body = resp.read().decode("utf-8")
|
|
86
|
+
return json.loads(body)
|
|
87
|
+
except urllib.error.HTTPError as e:
|
|
88
|
+
body = e.read().decode("utf-8", errors="replace")
|
|
89
|
+
try:
|
|
90
|
+
err = json.loads(body)
|
|
91
|
+
msg = err.get("error", body)
|
|
92
|
+
except Exception:
|
|
93
|
+
msg = body
|
|
94
|
+
if e.code in (401, 403):
|
|
95
|
+
print(f"Error: Invalid or expired API key (HTTP {e.code})", file=sys.stderr)
|
|
96
|
+
elif e.code == 402:
|
|
97
|
+
print(f"Error: {msg}", file=sys.stderr)
|
|
98
|
+
else:
|
|
99
|
+
print(f"Error: API returned HTTP {e.code}: {msg}", file=sys.stderr)
|
|
100
|
+
sys.exit(1)
|
|
101
|
+
except urllib.error.URLError as e:
|
|
102
|
+
print(f"Error: Could not reach Lokuma API: {e.reason}", file=sys.stderr)
|
|
103
|
+
sys.exit(1)
|
|
104
|
+
except json.JSONDecodeError as e:
|
|
105
|
+
print(f"Error: Invalid JSON response: {e}", file=sys.stderr)
|
|
106
|
+
sys.exit(1)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# ─────────────────────────────────────────────
|
|
110
|
+
# Output formatting
|
|
111
|
+
# ─────────────────────────────────────────────
|
|
112
|
+
|
|
113
|
+
def _format_output(result: dict, fmt: str) -> str:
|
|
114
|
+
if "error" in result:
|
|
115
|
+
return f"Error: {result['error']}"
|
|
116
|
+
|
|
117
|
+
# design-system response (has "output" key for ascii/markdown)
|
|
118
|
+
if "output" in result:
|
|
119
|
+
return result["output"]
|
|
120
|
+
|
|
121
|
+
# design-system json response
|
|
122
|
+
if "design_system" in result:
|
|
123
|
+
ds = result["design_system"]
|
|
124
|
+
if fmt == "json":
|
|
125
|
+
return json.dumps(ds, indent=2, ensure_ascii=False)
|
|
126
|
+
lines = [f"## Design System: {ds.get('project_name', '')}\n"]
|
|
127
|
+
for section, data in ds.items():
|
|
128
|
+
if section == "project_name":
|
|
129
|
+
continue
|
|
130
|
+
lines.append(f"### {section.replace('_', ' ').title()}")
|
|
131
|
+
if isinstance(data, dict):
|
|
132
|
+
for k, v in data.items():
|
|
133
|
+
lines.append(f"- **{k}**: {v}")
|
|
134
|
+
else:
|
|
135
|
+
lines.append(str(data))
|
|
136
|
+
lines.append("")
|
|
137
|
+
return "\n".join(lines)
|
|
138
|
+
|
|
139
|
+
# multi-domain response
|
|
140
|
+
if result.get("strategy") == "multi":
|
|
141
|
+
if fmt == "json":
|
|
142
|
+
return json.dumps(result, indent=2, ensure_ascii=False)
|
|
143
|
+
lines = [f"## Lokuma Design Results\n"]
|
|
144
|
+
for r in result.get("results", []):
|
|
145
|
+
domain = r.get("domain", "")
|
|
146
|
+
lines.append(f"### {domain.title()}")
|
|
147
|
+
for i, row in enumerate(r.get("results", []), 1):
|
|
148
|
+
lines.append(f"**{i}.** " + " | ".join(
|
|
149
|
+
f"{k}: {str(v)[:100]}" for k, v in list(row.items())[:4]
|
|
150
|
+
))
|
|
151
|
+
lines.append("")
|
|
152
|
+
return "\n".join(lines)
|
|
153
|
+
|
|
154
|
+
# single-domain response
|
|
155
|
+
if fmt == "json":
|
|
156
|
+
return json.dumps(result, indent=2, ensure_ascii=False)
|
|
157
|
+
|
|
158
|
+
lines = [f"## Lokuma — {result.get('domain', '').title()}\n"]
|
|
159
|
+
lines.append(f"**Query:** {result.get('query', '')}\n")
|
|
160
|
+
for i, row in enumerate(result.get("results", []), 1):
|
|
161
|
+
lines.append(f"### Result {i}")
|
|
162
|
+
for key, value in row.items():
|
|
163
|
+
v = str(value)
|
|
164
|
+
if len(v) > 300:
|
|
165
|
+
v = v[:300] + "..."
|
|
166
|
+
lines.append(f"- **{key}:** {v}")
|
|
167
|
+
lines.append("")
|
|
168
|
+
return "\n".join(lines)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
# ─────────────────────────────────────────────
|
|
172
|
+
# CLI
|
|
173
|
+
# ─────────────────────────────────────────────
|
|
174
|
+
|
|
175
|
+
def main():
|
|
176
|
+
parser = argparse.ArgumentParser(
|
|
177
|
+
description="Lokuma Design Intelligence",
|
|
178
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
179
|
+
epilog=__doc__,
|
|
180
|
+
)
|
|
181
|
+
parser.add_argument("query", help="Describe your product or design need in natural language")
|
|
182
|
+
parser.add_argument("--project-name", "-p", type=str, default=None,
|
|
183
|
+
help="Optional project name")
|
|
184
|
+
parser.add_argument("--format", "-f", choices=["ascii", "markdown", "json"],
|
|
185
|
+
default="ascii", help="Output format (default: ascii)")
|
|
186
|
+
|
|
187
|
+
args = parser.parse_args()
|
|
188
|
+
|
|
189
|
+
payload = {"query": args.query, "format": args.format}
|
|
190
|
+
if args.project_name:
|
|
191
|
+
payload["project_name"] = args.project_name
|
|
192
|
+
|
|
193
|
+
result = _post("design", payload)
|
|
194
|
+
print(_format_output(result, args.format))
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
if __name__ == "__main__":
|
|
198
|
+
main()
|
package/dist/index.js
CHANGED
|
@@ -54,29 +54,29 @@ var AI_DISPLAY_NAMES = {
|
|
|
54
54
|
all: "All assistants"
|
|
55
55
|
};
|
|
56
56
|
var AI_SKILL_PATHS = {
|
|
57
|
-
claude: { root: ".claude", skillMd: ".claude/skills/
|
|
58
|
-
cursor: { root: ".cursor", skillMd: ".cursor/rules/
|
|
59
|
-
windsurf: { root: ".windsurf", skillMd: ".windsurf/rules/
|
|
60
|
-
copilot: { root: ".github", skillMd: ".github/instructions/
|
|
61
|
-
kiro: { root: ".kiro", skillMd: ".kiro/steering/
|
|
62
|
-
roocode: { root: ".roo", skillMd: ".roo/rules/
|
|
63
|
-
codex: { root: ".codex", skillMd: ".codex/instructions.md", scriptPy: ".codex/
|
|
64
|
-
qoder: { root: ".qoder", skillMd: ".qoder/rules/
|
|
65
|
-
gemini: { root: ".gemini", skillMd: ".gemini/GEMINI.md", scriptPy: ".gemini/
|
|
66
|
-
trae: { root: ".trae", skillMd: ".trae/rules/
|
|
67
|
-
opencode: { root: ".opencode", skillMd: ".opencode/OPENCODE.md", scriptPy: ".opencode/
|
|
68
|
-
continue: { root: ".continue", skillMd: ".continue/
|
|
69
|
-
codebuddy: { root: ".codebuddy", skillMd: ".codebuddy/
|
|
70
|
-
droid: { root: ".factory", skillMd: ".factory/skills/
|
|
57
|
+
claude: { root: ".claude", skillMd: ".claude/skills/lokuma/SKILL.md", scriptPy: ".claude/skills/lokuma/scripts/search.py" },
|
|
58
|
+
cursor: { root: ".cursor", skillMd: ".cursor/rules/lokuma.mdc", scriptPy: ".cursor/rules/lokuma/scripts/search.py" },
|
|
59
|
+
windsurf: { root: ".windsurf", skillMd: ".windsurf/rules/lokuma.md", scriptPy: ".windsurf/rules/lokuma/scripts/search.py" },
|
|
60
|
+
copilot: { root: ".github", skillMd: ".github/instructions/lokuma.instructions.md", scriptPy: ".github/instructions/lokuma/scripts/search.py" },
|
|
61
|
+
kiro: { root: ".kiro", skillMd: ".kiro/steering/lokuma.md", scriptPy: ".kiro/steering/lokuma/scripts/search.py" },
|
|
62
|
+
roocode: { root: ".roo", skillMd: ".roo/rules/lokuma.md", scriptPy: ".roo/rules/lokuma/scripts/search.py" },
|
|
63
|
+
codex: { root: ".codex", skillMd: ".codex/instructions.md", scriptPy: ".codex/lokuma/scripts/search.py" },
|
|
64
|
+
qoder: { root: ".qoder", skillMd: ".qoder/rules/lokuma.md", scriptPy: ".qoder/rules/lokuma/scripts/search.py" },
|
|
65
|
+
gemini: { root: ".gemini", skillMd: ".gemini/GEMINI.md", scriptPy: ".gemini/lokuma/scripts/search.py" },
|
|
66
|
+
trae: { root: ".trae", skillMd: ".trae/rules/lokuma.md", scriptPy: ".trae/rules/lokuma/scripts/search.py" },
|
|
67
|
+
opencode: { root: ".opencode", skillMd: ".opencode/OPENCODE.md", scriptPy: ".opencode/lokuma/scripts/search.py" },
|
|
68
|
+
continue: { root: ".continue", skillMd: ".continue/lokuma/SKILL.md", scriptPy: ".continue/lokuma/scripts/search.py" },
|
|
69
|
+
codebuddy: { root: ".codebuddy", skillMd: ".codebuddy/lokuma/SKILL.md", scriptPy: ".codebuddy/lokuma/scripts/search.py" },
|
|
70
|
+
droid: { root: ".factory", skillMd: ".factory/skills/lokuma/SKILL.md", scriptPy: ".factory/skills/lokuma/scripts/search.py" },
|
|
71
71
|
// OpenClaw installs to a fixed absolute path (not relative to cwd)
|
|
72
|
-
openclaw: { root: "~/.openclaw/workspace/skills/
|
|
72
|
+
openclaw: { root: "~/.openclaw/workspace/skills/lokuma", skillMd: "~/.openclaw/workspace/skills/lokuma/SKILL.md", scriptPy: "~/.openclaw/workspace/skills/lokuma/scripts/search.py" }
|
|
73
73
|
};
|
|
74
74
|
|
|
75
75
|
// src/commands/init.ts
|
|
76
76
|
import { createRequire } from "node:module";
|
|
77
77
|
var _require = createRequire(import.meta.url);
|
|
78
78
|
var _pkgDir = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
79
|
-
var
|
|
79
|
+
var DESIGN_PY = readFileSync(join(_pkgDir, "assets", "design.py"), "utf-8");
|
|
80
80
|
function resolvePath(p) {
|
|
81
81
|
if (p.startsWith("~/")) return join(homedir(), p.slice(2));
|
|
82
82
|
return p;
|
|
@@ -88,8 +88,8 @@ description: >
|
|
|
88
88
|
Lokuma design intelligence. Use this skill whenever building or modifying UI:
|
|
89
89
|
landing pages, dashboards, SaaS products, mobile apps, e-commerce, portfolios,
|
|
90
90
|
admin panels, onboarding flows, settings screens, pricing pages, forms, charts,
|
|
91
|
-
and design systems.
|
|
92
|
-
|
|
91
|
+
and design systems. Describe the product, audience, platform, tone, and goal
|
|
92
|
+
in natural language. Lokuma will decide the best design route automatically.
|
|
93
93
|
---
|
|
94
94
|
|
|
95
95
|
# Lokuma \u2014 Design Intelligence Skill
|
|
@@ -123,119 +123,55 @@ Get your key at **https://lokuma.ai**
|
|
|
123
123
|
|
|
124
124
|
---
|
|
125
125
|
|
|
126
|
-
## How to
|
|
126
|
+
## How to Use Lokuma
|
|
127
127
|
|
|
128
|
-
**
|
|
128
|
+
**Do not decide between design-system, domain search, or routing yourself.**
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
If the task is about UI, design, layout, colors, typography, UX, landing pages, charts, or visual direction:
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
- What platform it lives on (web, mobile app, dashboard, landing page)
|
|
136
|
-
- What feeling or brand tone it should convey
|
|
137
|
-
- Any special goals (conversion, trust, clarity, premium feel, speed, playfulness)
|
|
132
|
+
1. Keep the user's request in natural language
|
|
133
|
+
2. Pass it directly to Lokuma
|
|
134
|
+
3. Lokuma will decide the best route in the cloud automatically
|
|
138
135
|
|
|
139
|
-
###
|
|
140
|
-
- "A meditation and sleep mobile app for young professionals. Calm, premium, organic, not too clinical."
|
|
141
|
-
- "A landing page for an AI note-taking SaaS. Clean, modern, trustworthy, conversion-focused."
|
|
142
|
-
- "A fintech dashboard for small businesses. Professional, data-dense, readable, high trust."
|
|
143
|
-
- "An e-commerce brand for handmade skincare. Warm, soft, elegant, natural, slightly editorial."
|
|
144
|
-
|
|
145
|
-
### Better results if you include
|
|
146
|
-
- **Product**: what it is
|
|
147
|
-
- **Audience**: who uses it
|
|
148
|
-
- **Platform**: app / web / dashboard / landing / admin
|
|
149
|
-
- **Tone**: calm / playful / bold / premium / trustworthy / minimal / editorial
|
|
150
|
-
- **Goal**: conversion / retention / clarity / efficiency / immersion / delight
|
|
151
|
-
|
|
152
|
-
---
|
|
153
|
-
|
|
154
|
-
## Recommended Workflow
|
|
155
|
-
|
|
156
|
-
### 1) Start with design system
|
|
157
|
-
For any new project, new page, or fuzzy design request, start here:
|
|
136
|
+
### Preferred command
|
|
158
137
|
|
|
159
138
|
\`\`\`bash
|
|
160
|
-
python3 ${scriptPath} "<natural language
|
|
139
|
+
python3 ${scriptPath} "<natural language design request>"
|
|
161
140
|
\`\`\`
|
|
162
141
|
|
|
163
|
-
|
|
142
|
+
Optional:
|
|
164
143
|
|
|
165
144
|
\`\`\`bash
|
|
166
|
-
python3 ${scriptPath} "
|
|
167
|
-
|
|
168
|
-
python3 ${scriptPath} "
|
|
145
|
+
python3 ${scriptPath} "<natural language design request>" -p "Project Name"
|
|
146
|
+
python3 ${scriptPath} "<natural language design request>" -f json
|
|
147
|
+
python3 ${scriptPath} "<natural language design request>" -f markdown
|
|
169
148
|
\`\`\`
|
|
170
149
|
|
|
171
|
-
|
|
172
|
-
- page / conversion pattern
|
|
173
|
-
- visual style
|
|
174
|
-
- color direction
|
|
175
|
-
- typography
|
|
176
|
-
- key effects
|
|
177
|
-
- anti-patterns to avoid
|
|
178
|
-
|
|
179
|
-
### 2) Use domain search for focused follow-up
|
|
180
|
-
After design-system, use targeted search only when you want more detail in one area.
|
|
181
|
-
|
|
182
|
-
\`\`\`bash
|
|
183
|
-
python3 ${scriptPath} "<design need>" --domain <domain> [-n <count>]
|
|
184
|
-
\`\`\`
|
|
185
|
-
|
|
186
|
-
| Domain | Use it when you want... |
|
|
187
|
-
|--------|--------------------------|
|
|
188
|
-
| \`style\` | visual direction / aesthetic language |
|
|
189
|
-
| \`color\` | palettes / mood / brand color strategy |
|
|
190
|
-
| \`typography\` | font pairing and hierarchy |
|
|
191
|
-
| \`product\` | industry-specific design patterns |
|
|
192
|
-
| \`reasoning\` | design logic and decision support |
|
|
193
|
-
| \`ux\` | usability, accessibility, interaction best practices |
|
|
194
|
-
| \`chart\` | data visualization type recommendations |
|
|
195
|
-
| \`landing\` | landing page structure and CTA strategy |
|
|
196
|
-
| \`icons\` | icon style / library suggestions |
|
|
197
|
-
| \`google-fonts\` | specific Google Font discovery |
|
|
198
|
-
|
|
199
|
-
Examples:
|
|
150
|
+
---
|
|
200
151
|
|
|
201
|
-
|
|
202
|
-
python3 ${scriptPath} "Need a calm but premium color direction for a wellness app" --domain color
|
|
203
|
-
python3 ${scriptPath} "What typography fits a luxury skincare brand with an editorial feel?" --domain typography
|
|
204
|
-
python3 ${scriptPath} "Best landing page structure for an AI productivity SaaS that needs signups" --domain landing
|
|
205
|
-
python3 ${scriptPath} "UX risks in a mobile checkout flow with address, payment, and promo code" --domain ux
|
|
206
|
-
\`\`\`
|
|
152
|
+
## Good Input Examples
|
|
207
153
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
154
|
+
- "A meditation and sleep mobile app for young professionals. Calm, premium, organic, not too clinical."
|
|
155
|
+
- "A landing page for an AI note-taking SaaS. Clean, modern, trustworthy, conversion-focused."
|
|
156
|
+
- "A fintech dashboard for small businesses. Professional, data-dense, readable, high trust."
|
|
157
|
+
- "An e-commerce brand for handmade skincare. Warm, soft, elegant, natural, slightly editorial."
|
|
158
|
+
- "What color palette fits a luxury skincare brand?"
|
|
159
|
+
- "Best font pairing for a modern fintech dashboard"
|
|
160
|
+
- "How should I structure a landing page for an AI sales tool?"
|
|
214
161
|
|
|
215
162
|
---
|
|
216
163
|
|
|
217
164
|
## Practical Advice for AI Coding Assistants
|
|
218
165
|
|
|
219
166
|
### Prefer the user's original language
|
|
220
|
-
If the user already described what they want clearly, pass that directly into Lokuma. Do **not** aggressively compress it into keywords
|
|
221
|
-
|
|
222
|
-
### Use design-system first when the task is broad
|
|
223
|
-
If the user says things like:
|
|
224
|
-
- "build a landing page"
|
|
225
|
-
- "make this app feel more premium"
|
|
226
|
-
- "what style should this dashboard use"
|
|
227
|
-
- "design a fintech onboarding flow"
|
|
167
|
+
If the user already described what they want clearly, pass that directly into Lokuma. Do **not** aggressively compress it into keywords.
|
|
228
168
|
|
|
229
|
-
|
|
169
|
+
### One entry point
|
|
170
|
+
Do not manually choose between domain search and design-system generation.
|
|
171
|
+
Lokuma handles that automatically in the cloud.
|
|
230
172
|
|
|
231
|
-
### Use
|
|
232
|
-
If the user
|
|
233
|
-
- a palette
|
|
234
|
-
- a font direction
|
|
235
|
-
- a chart type
|
|
236
|
-
- UX review notes
|
|
237
|
-
|
|
238
|
-
then use a focused domain query.
|
|
173
|
+
### Use Lokuma early
|
|
174
|
+
If the user is still fuzzy about style, tone, layout, color, hierarchy, brand feel, or UX direction, use Lokuma before generating code.
|
|
239
175
|
|
|
240
176
|
---
|
|
241
177
|
|
|
@@ -243,34 +179,19 @@ then use a focused domain query.
|
|
|
243
179
|
|
|
244
180
|
\`\`\`bash
|
|
245
181
|
# Full product direction
|
|
246
|
-
python3 ${scriptPath} "A wellness subscription app for burnout recovery. Soft, warm, calming, organic, habit-forming."
|
|
247
|
-
|
|
248
|
-
# Landing page strategy
|
|
249
|
-
python3 ${scriptPath} "A homepage for an AI coding assistant targeting startups. High trust, fast clarity, strong CTA." --domain landing
|
|
182
|
+
python3 ${scriptPath} "A wellness subscription app for burnout recovery. Soft, warm, calming, organic, habit-forming." -p "Exhale"
|
|
250
183
|
|
|
251
|
-
#
|
|
252
|
-
python3 ${scriptPath} "A
|
|
184
|
+
# Landing page / conversion direction
|
|
185
|
+
python3 ${scriptPath} "A homepage for an AI coding assistant targeting startups. High trust, fast clarity, strong CTA."
|
|
253
186
|
|
|
254
|
-
#
|
|
255
|
-
python3 ${scriptPath} "A
|
|
187
|
+
# Visual design question
|
|
188
|
+
python3 ${scriptPath} "A creative portfolio site for a motion designer. Bold, editorial, experimental, but still readable."
|
|
256
189
|
|
|
257
|
-
#
|
|
258
|
-
python3 ${scriptPath} "A
|
|
259
|
-
\`\`\`
|
|
260
|
-
|
|
261
|
-
---
|
|
190
|
+
# Color question
|
|
191
|
+
python3 ${scriptPath} "A secure but friendly fintech app for freelancers"
|
|
262
192
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
\`\`\`bash
|
|
266
|
-
# JSON (best for programmatic use)
|
|
267
|
-
python3 ${scriptPath} "A fintech mobile app for young investors" --design-system -f json
|
|
268
|
-
|
|
269
|
-
# Markdown (best for docs / notes)
|
|
270
|
-
python3 ${scriptPath} "A fintech mobile app for young investors" --design-system -f markdown
|
|
271
|
-
|
|
272
|
-
# ASCII (default terminal output)
|
|
273
|
-
python3 ${scriptPath} "A fintech mobile app for young investors" --design-system
|
|
193
|
+
# UX question
|
|
194
|
+
python3 ${scriptPath} "A mobile onboarding flow with permissions, account creation, and trust concerns"
|
|
274
195
|
\`\`\`
|
|
275
196
|
|
|
276
197
|
---
|
|
@@ -330,21 +251,29 @@ async function initCommand(options) {
|
|
|
330
251
|
await mkdir(dirname(paths.skillMd), { recursive: true });
|
|
331
252
|
await mkdir(dirname(paths.scriptPy), { recursive: true });
|
|
332
253
|
await writeFile(paths.skillMd, buildSkillMd(paths.scriptPy), "utf-8");
|
|
333
|
-
await writeFile(paths.scriptPy,
|
|
334
|
-
installed.push(AI_DISPLAY_NAMES[t]);
|
|
254
|
+
await writeFile(paths.scriptPy, DESIGN_PY, "utf-8");
|
|
255
|
+
installed.push({ name: AI_DISPLAY_NAMES[t], skillMd: paths.skillMd, scriptPy: paths.scriptPy });
|
|
335
256
|
}
|
|
336
257
|
spinner.succeed("Done!");
|
|
337
258
|
if (installed.length > 0) {
|
|
338
259
|
console.log();
|
|
339
|
-
|
|
260
|
+
for (const item of installed) {
|
|
261
|
+
console.log(chalk.green(` \u2713 ${item.name}`));
|
|
262
|
+
console.log(chalk.dim(` skill : ${item.skillMd}`));
|
|
263
|
+
console.log(chalk.dim(` design: ${item.scriptPy}`));
|
|
264
|
+
}
|
|
340
265
|
}
|
|
341
266
|
console.log();
|
|
342
267
|
console.log(chalk.bold(" Next steps:"));
|
|
343
268
|
console.log(chalk.dim(" 1. Set your API key:"));
|
|
344
269
|
console.log(chalk.cyan(" export LOKUMA_API_KEY=lokuma_your_key_here"));
|
|
345
|
-
console.log(chalk.dim(" 2. Get a key \u2192 https://lokuma.
|
|
270
|
+
console.log(chalk.dim(" 2. Get a key \u2192 https://lokuma.ai"));
|
|
346
271
|
console.log(chalk.dim(" 3. Restart your AI assistant"));
|
|
347
|
-
console.log(
|
|
272
|
+
console.log();
|
|
273
|
+
console.log(chalk.bold(" Try it now \u2014 tell your AI assistant:"));
|
|
274
|
+
console.log(chalk.cyan(' "Build a coffee shop website by lokuma"'));
|
|
275
|
+
console.log(chalk.dim(' "Design a landing page for a SaaS startup by lokuma"'));
|
|
276
|
+
console.log(chalk.dim(' "Create a mobile app UI for a meditation app by lokuma"'));
|
|
348
277
|
console.log();
|
|
349
278
|
} catch (err) {
|
|
350
279
|
spinner.fail("Installation failed");
|