thachvd-kit 1.0.0 → 1.0.1
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.md +30 -19
- package/agents/frontend-specialist.md +2 -2
- package/agents/mobile-developer.md +4 -4
- package/bin/cli.js +340 -118
- package/package.json +43 -19
- package/rules/GEMINI.md +5 -3
- package/scripts/init.py +317 -122
- package/skills/desktop-design/SKILL.md +25 -0
- package/skills/react-frontend/SKILL.md +25 -0
- package/.shared/ui-ux-pro-max/data/charts.csv +0 -26
- package/.shared/ui-ux-pro-max/data/colors.csv +0 -97
- package/.shared/ui-ux-pro-max/data/icons.csv +0 -101
- package/.shared/ui-ux-pro-max/data/landing.csv +0 -31
- package/.shared/ui-ux-pro-max/data/products.csv +0 -97
- package/.shared/ui-ux-pro-max/data/prompts.csv +0 -24
- package/.shared/ui-ux-pro-max/data/react-performance.csv +0 -45
- package/.shared/ui-ux-pro-max/data/stacks/flutter.csv +0 -53
- package/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +0 -56
- package/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +0 -53
- package/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +0 -53
- package/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +0 -51
- package/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +0 -59
- package/.shared/ui-ux-pro-max/data/stacks/react-native.csv +0 -52
- package/.shared/ui-ux-pro-max/data/stacks/react.csv +0 -54
- package/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +0 -61
- package/.shared/ui-ux-pro-max/data/stacks/svelte.csv +0 -54
- package/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +0 -51
- package/.shared/ui-ux-pro-max/data/stacks/vue.csv +0 -50
- package/.shared/ui-ux-pro-max/data/styles.csv +0 -59
- package/.shared/ui-ux-pro-max/data/typography.csv +0 -58
- package/.shared/ui-ux-pro-max/data/ui-reasoning.csv +0 -101
- package/.shared/ui-ux-pro-max/data/ux-guidelines.csv +0 -100
- package/.shared/ui-ux-pro-max/data/web-interface.csv +0 -31
- package/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
- package/.shared/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-313.pyc +0 -0
- package/.shared/ui-ux-pro-max/scripts/core.py +0 -258
- package/.shared/ui-ux-pro-max/scripts/design_system.py +0 -1067
- package/.shared/ui-ux-pro-max/scripts/search.py +0 -106
- package/ARCHITECTURE.md +0 -288
- package/CLAUDE.md +0 -90
- package/mcp_config.json +0 -24
package/scripts/init.py
CHANGED
|
@@ -9,11 +9,12 @@ Usage:
|
|
|
9
9
|
python scripts/init.py --platform claude # Only CLAUDE.md
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
|
-
import sys
|
|
13
|
-
import os
|
|
14
|
-
import argparse
|
|
15
|
-
|
|
16
|
-
from
|
|
12
|
+
import sys
|
|
13
|
+
import os
|
|
14
|
+
import argparse
|
|
15
|
+
import json
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from datetime import datetime
|
|
17
18
|
|
|
18
19
|
# ─── Color helpers ──────────────────────────────────────────────────────────
|
|
19
20
|
|
|
@@ -53,13 +54,17 @@ def ask_multi(prompt, choices, default=None):
|
|
|
53
54
|
selected.append(part) # allow free-text
|
|
54
55
|
return selected
|
|
55
56
|
|
|
56
|
-
def ask_bool(prompt, default=True):
|
|
57
|
+
def ask_bool(prompt, default=True):
|
|
57
58
|
"""Yes/no prompt."""
|
|
58
59
|
default_str = "Y/n" if default else "y/N"
|
|
59
60
|
val = input(f" {bold('→')} {prompt} [{dim(default_str)}]: ").strip().lower()
|
|
60
|
-
if not val:
|
|
61
|
-
return default
|
|
62
|
-
return val.startswith("y")
|
|
61
|
+
if not val:
|
|
62
|
+
return default
|
|
63
|
+
return val.startswith("y")
|
|
64
|
+
|
|
65
|
+
def ask_select(prompt, choices, default=None):
|
|
66
|
+
default = default or choices[0]
|
|
67
|
+
return ask(prompt, default=default, choices=choices)
|
|
63
68
|
|
|
64
69
|
def section(title):
|
|
65
70
|
print(f"\n{bold(cyan('━━ ' + title + ' '))}")
|
|
@@ -79,10 +84,10 @@ LANG_SKILLS = {
|
|
|
79
84
|
"csharp": ["api-design"],
|
|
80
85
|
}
|
|
81
86
|
|
|
82
|
-
FRAMEWORK_SKILLS = {
|
|
83
|
-
"vue": ["frontend-design", "tailwind-patterns"],
|
|
84
|
-
"react": ["
|
|
85
|
-
"next": ["nextjs-react-expert", "frontend-design"],
|
|
87
|
+
FRAMEWORK_SKILLS = {
|
|
88
|
+
"vue": ["frontend-design", "tailwind-patterns"],
|
|
89
|
+
"react": ["react-frontend", "frontend-design"],
|
|
90
|
+
"next": ["nextjs-react-expert", "frontend-design"],
|
|
86
91
|
"nuxt": ["frontend-design"],
|
|
87
92
|
"svelte": ["frontend-design"],
|
|
88
93
|
"laravel": ["laravel-patterns", "laravel-security", "laravel-tdd"],
|
|
@@ -91,12 +96,12 @@ FRAMEWORK_SKILLS = {
|
|
|
91
96
|
"django": ["python-patterns", "api-design"],
|
|
92
97
|
"gin": ["golang-patterns", "golang-testing"],
|
|
93
98
|
"fiber": ["golang-patterns", "golang-testing"],
|
|
94
|
-
"tauri": ["rust-pro", "
|
|
95
|
-
"flutter": ["mobile-design"],
|
|
96
|
-
"react-native": ["mobile-design"],
|
|
97
|
-
}
|
|
99
|
+
"tauri": ["rust-pro", "desktop-design"],
|
|
100
|
+
"flutter": ["mobile-design"],
|
|
101
|
+
"react-native": ["mobile-design"],
|
|
102
|
+
}
|
|
98
103
|
|
|
99
|
-
INFRA_SKILLS = {
|
|
104
|
+
INFRA_SKILLS = {
|
|
100
105
|
"docker": ["docker-patterns"],
|
|
101
106
|
"aws": ["deployment-procedures", "docker-patterns"],
|
|
102
107
|
"gcp": ["deployment-procedures", "docker-patterns"],
|
|
@@ -120,7 +125,157 @@ def resolve_skills(data):
|
|
|
120
125
|
if key in infra_lower:
|
|
121
126
|
skills.update(vals)
|
|
122
127
|
skills.update(["clean-code", "systematic-debugging"])
|
|
123
|
-
return sorted(skills)
|
|
128
|
+
return sorted(skills)
|
|
129
|
+
|
|
130
|
+
FRAMEWORKS_ALL = ["vue", "react", "next", "nuxt", "svelte", "angular",
|
|
131
|
+
"laravel", "express", "fastapi", "django", "gin", "fiber", "nestjs",
|
|
132
|
+
"tauri", "flutter", "react-native"]
|
|
133
|
+
LANGUAGES_ALL = ["typescript", "javascript", "python", "go", "php", "rust", "java", "swift", "kotlin", "csharp", "c", "cpp"]
|
|
134
|
+
PROJECT_TYPES_ALL = ["web-app", "api", "mobile", "desktop", "cli", "library", "fullstack"]
|
|
135
|
+
DATABASES_ALL = ["postgres", "mysql", "sqlite", "mongodb", "redis", "dynamodb", "supabase", "prisma", "none"]
|
|
136
|
+
PACKAGE_MANAGERS_ALL = ["npm", "pnpm", "yarn", "bun", "pip", "uv", "poetry", "go mod", "cargo", "composer", "auto-detect"]
|
|
137
|
+
TEST_FRAMEWORKS_ALL = ["jest", "vitest", "pytest", "go test", "phpunit", "pest", "rspec", "junit", "auto-detect"]
|
|
138
|
+
CLOUDS_ALL = ["aws", "gcp", "azure", "vercel", "fly", "railway", "digitalocean", "none"]
|
|
139
|
+
|
|
140
|
+
def read_text_if_exists(*parts):
|
|
141
|
+
path = Path.cwd().joinpath(*parts)
|
|
142
|
+
try:
|
|
143
|
+
return path.read_text(encoding="utf-8") if path.exists() else ""
|
|
144
|
+
except Exception:
|
|
145
|
+
return ""
|
|
146
|
+
|
|
147
|
+
def read_json_if_exists(*parts):
|
|
148
|
+
path = Path.cwd().joinpath(*parts)
|
|
149
|
+
try:
|
|
150
|
+
return json.loads(path.read_text(encoding="utf-8")) if path.exists() else None
|
|
151
|
+
except Exception:
|
|
152
|
+
return None
|
|
153
|
+
|
|
154
|
+
def detect_package_manager():
|
|
155
|
+
cwd = Path.cwd()
|
|
156
|
+
if (cwd / "pnpm-lock.yaml").exists(): return "pnpm"
|
|
157
|
+
if (cwd / "yarn.lock").exists(): return "yarn"
|
|
158
|
+
if (cwd / "bun.lockb").exists() or (cwd / "bun.lock").exists(): return "bun"
|
|
159
|
+
if (cwd / "package-lock.json").exists(): return "npm"
|
|
160
|
+
if (cwd / "uv.lock").exists(): return "uv"
|
|
161
|
+
if (cwd / "poetry.lock").exists(): return "poetry"
|
|
162
|
+
if (cwd / "requirements.txt").exists() or (cwd / "pyproject.toml").exists(): return "pip"
|
|
163
|
+
if (cwd / "go.mod").exists(): return "go mod"
|
|
164
|
+
if (cwd / "Cargo.toml").exists(): return "cargo"
|
|
165
|
+
if (cwd / "composer.json").exists(): return "composer"
|
|
166
|
+
return "auto-detect"
|
|
167
|
+
|
|
168
|
+
def uniq(values):
|
|
169
|
+
return list(dict.fromkeys(v for v in values if v))
|
|
170
|
+
|
|
171
|
+
def scan_project():
|
|
172
|
+
pkg = read_json_if_exists("package.json") or {}
|
|
173
|
+
deps = {}
|
|
174
|
+
for key in ("dependencies", "devDependencies", "peerDependencies"):
|
|
175
|
+
deps.update(pkg.get(key, {}) or {})
|
|
176
|
+
dep_names = set(deps.keys())
|
|
177
|
+
frameworks = []
|
|
178
|
+
infrastructure = []
|
|
179
|
+
primary_language = ""
|
|
180
|
+
project_type = ""
|
|
181
|
+
database = "none"
|
|
182
|
+
test_framework = "auto-detect"
|
|
183
|
+
cloud = "none"
|
|
184
|
+
ci_cd = "none"
|
|
185
|
+
|
|
186
|
+
def add_framework(name, condition):
|
|
187
|
+
if condition:
|
|
188
|
+
frameworks.append(name)
|
|
189
|
+
|
|
190
|
+
requirements = read_text_if_exists("requirements.txt")
|
|
191
|
+
go_mod = read_text_if_exists("go.mod")
|
|
192
|
+
pubspec = read_text_if_exists("pubspec.yaml")
|
|
193
|
+
|
|
194
|
+
add_framework("next", "next" in dep_names)
|
|
195
|
+
add_framework("react", "react" in dep_names)
|
|
196
|
+
add_framework("vue", "vue" in dep_names)
|
|
197
|
+
add_framework("nuxt", "nuxt" in dep_names)
|
|
198
|
+
add_framework("svelte", "svelte" in dep_names or "@sveltejs/kit" in dep_names)
|
|
199
|
+
add_framework("angular", "@angular/core" in dep_names)
|
|
200
|
+
add_framework("express", "express" in dep_names)
|
|
201
|
+
add_framework("nestjs", "@nestjs/core" in dep_names)
|
|
202
|
+
add_framework("fastapi", "fastapi" in requirements.lower())
|
|
203
|
+
add_framework("django", "django" in requirements.lower())
|
|
204
|
+
add_framework("tauri", "@tauri-apps/api" in dep_names or Path("src-tauri/tauri.conf.json").exists() or Path("src-tauri/tauri.conf.json5").exists())
|
|
205
|
+
add_framework("flutter", "flutter:" in pubspec.lower())
|
|
206
|
+
add_framework("react-native", "react-native" in dep_names or "expo" in dep_names)
|
|
207
|
+
add_framework("laravel", Path("artisan").exists())
|
|
208
|
+
add_framework("gin", "github.com/gin-gonic/gin" in go_mod.lower())
|
|
209
|
+
add_framework("fiber", "github.com/gofiber/fiber" in go_mod.lower())
|
|
210
|
+
|
|
211
|
+
if Path("tsconfig.json").exists() or "typescript" in dep_names: primary_language = "typescript"
|
|
212
|
+
elif Path("Cargo.toml").exists() or Path("src-tauri/Cargo.toml").exists(): primary_language = "rust"
|
|
213
|
+
elif Path("go.mod").exists(): primary_language = "go"
|
|
214
|
+
elif Path("requirements.txt").exists() or Path("pyproject.toml").exists(): primary_language = "python"
|
|
215
|
+
elif Path("composer.json").exists(): primary_language = "php"
|
|
216
|
+
elif dep_names or Path("package.json").exists(): primary_language = "javascript"
|
|
217
|
+
|
|
218
|
+
if "tauri" in frameworks: project_type = "desktop"
|
|
219
|
+
elif "flutter" in frameworks or "react-native" in frameworks: project_type = "mobile"
|
|
220
|
+
elif any(f in frameworks for f in ["express", "fastapi", "django", "laravel", "gin", "fiber", "nestjs"]):
|
|
221
|
+
project_type = "fullstack" if any(f in frameworks for f in ["react", "next", "vue", "nuxt", "svelte", "angular"]) else "api"
|
|
222
|
+
elif any(f in frameworks for f in ["react", "next", "vue", "nuxt", "svelte", "angular"]):
|
|
223
|
+
project_type = "web-app"
|
|
224
|
+
elif Path("package.json").exists() and pkg.get("bin"):
|
|
225
|
+
project_type = "cli"
|
|
226
|
+
|
|
227
|
+
if "pg" in dep_names or "postgres" in dep_names or "@prisma/client" in dep_names or "postgres" in json.dumps(pkg).lower(): database = "postgres"
|
|
228
|
+
elif "mysql" in dep_names or "mysql2" in dep_names: database = "mysql"
|
|
229
|
+
elif "sqlite3" in dep_names or "better-sqlite3" in dep_names or "rusqlite" in dep_names: database = "sqlite"
|
|
230
|
+
elif "mongodb" in dep_names or "mongoose" in dep_names: database = "mongodb"
|
|
231
|
+
elif "redis" in dep_names or "ioredis" in dep_names: database = "redis"
|
|
232
|
+
elif "@aws-sdk/client-dynamodb" in dep_names: database = "dynamodb"
|
|
233
|
+
|
|
234
|
+
if "vitest" in dep_names: test_framework = "vitest"
|
|
235
|
+
elif "jest" in dep_names: test_framework = "jest"
|
|
236
|
+
elif "pytest" in dep_names or "pytest" in requirements.lower(): test_framework = "pytest"
|
|
237
|
+
elif "phpunit" in dep_names: test_framework = "phpunit"
|
|
238
|
+
elif "pest" in dep_names: test_framework = "pest"
|
|
239
|
+
elif Path("go.mod").exists(): test_framework = "go test"
|
|
240
|
+
|
|
241
|
+
if Path("Dockerfile").exists() or Path("docker-compose.yml").exists() or Path("docker-compose.yaml").exists():
|
|
242
|
+
infrastructure.append("docker")
|
|
243
|
+
|
|
244
|
+
if Path("vercel.json").exists():
|
|
245
|
+
cloud = "vercel"
|
|
246
|
+
infrastructure.append("vercel")
|
|
247
|
+
elif Path("fly.toml").exists():
|
|
248
|
+
cloud = "fly"
|
|
249
|
+
infrastructure.append("fly")
|
|
250
|
+
elif Path("railway.json").exists() or Path("railway.toml").exists():
|
|
251
|
+
cloud = "railway"
|
|
252
|
+
infrastructure.append("railway")
|
|
253
|
+
|
|
254
|
+
if Path(".github/workflows").exists(): ci_cd = "github-actions"
|
|
255
|
+
elif Path(".gitlab-ci.yml").exists(): ci_cd = "gitlab-ci"
|
|
256
|
+
elif Path(".circleci/config.yml").exists(): ci_cd = "circleci"
|
|
257
|
+
elif Path("Jenkinsfile").exists(): ci_cd = "jenkins"
|
|
258
|
+
|
|
259
|
+
return {
|
|
260
|
+
"project_name": Path.cwd().name,
|
|
261
|
+
"description": pkg.get("description", "A software project"),
|
|
262
|
+
"project_type": project_type if project_type in PROJECT_TYPES_ALL else "web-app",
|
|
263
|
+
"primary_language": primary_language if primary_language in LANGUAGES_ALL else "typescript",
|
|
264
|
+
"frameworks": uniq(frameworks),
|
|
265
|
+
"database": database if database in DATABASES_ALL else "none",
|
|
266
|
+
"package_manager": detect_package_manager(),
|
|
267
|
+
"uses_docker": "docker" in infrastructure,
|
|
268
|
+
"cloud": cloud,
|
|
269
|
+
"infrastructure": uniq(infrastructure),
|
|
270
|
+
"ci_cd": ci_cd,
|
|
271
|
+
"test_framework": test_framework if test_framework in TEST_FRAMEWORKS_ALL else "auto-detect",
|
|
272
|
+
"max_file_lines": "300",
|
|
273
|
+
"code_style": "project-standard",
|
|
274
|
+
"architecture_notes": "<!-- Add notes -->",
|
|
275
|
+
"current_phase": "Initial setup",
|
|
276
|
+
"next_phase": "—",
|
|
277
|
+
"known_issues": "<!-- None yet -->",
|
|
278
|
+
}
|
|
124
279
|
|
|
125
280
|
def resolve_agent_table(data):
|
|
126
281
|
rows = []
|
|
@@ -252,11 +407,12 @@ def generate_claude_md(data):
|
|
|
252
407
|
{data['description']}
|
|
253
408
|
Stack: {data['primary_language']} | {', '.join(data.get('frameworks', []))}
|
|
254
409
|
|
|
255
|
-
## Rules
|
|
256
|
-
- Read PROJECT_CONTEXT.md first for stack details and agent routing.
|
|
257
|
-
-
|
|
258
|
-
-
|
|
259
|
-
-
|
|
410
|
+
## Rules
|
|
411
|
+
- Read PROJECT_CONTEXT.md first for stack details and agent routing.
|
|
412
|
+
- If PROJECT_CONTEXT.md is missing or stale, create/update it before major work.
|
|
413
|
+
- Follow skills in .claude/skills/ (or skills/ if using Antigravity).
|
|
414
|
+
- Tests are mandatory. Verify before claiming done.
|
|
415
|
+
- Max {data.get('max_file_lines', '300')} lines per file.
|
|
260
416
|
|
|
261
417
|
## Key Skills
|
|
262
418
|
- Plan: `plan-writing` → `executing-plans`
|
|
@@ -275,19 +431,20 @@ See PROJECT_CONTEXT.md for full agent routing table.
|
|
|
275
431
|
|
|
276
432
|
# ─── Main wizard ─────────────────────────────────────────────────────────────
|
|
277
433
|
|
|
278
|
-
def main():
|
|
279
|
-
parser = argparse.ArgumentParser(description="thachvd-kit project init wizard")
|
|
280
|
-
parser.add_argument("--platform", choices=["antigravity", "claude", "all"], default="antigravity",
|
|
281
|
-
help="Which platform config to generate (default: antigravity)")
|
|
282
|
-
parser.add_argument("--yes", "-y", action="store_true", help="Use defaults without prompting")
|
|
283
|
-
|
|
434
|
+
def main():
|
|
435
|
+
parser = argparse.ArgumentParser(description="thachvd-kit project init wizard")
|
|
436
|
+
parser.add_argument("--platform", choices=["antigravity", "claude", "all"], default="antigravity",
|
|
437
|
+
help="Which platform config to generate (default: antigravity)")
|
|
438
|
+
parser.add_argument("--yes", "-y", action="store_true", help="Use defaults without prompting")
|
|
439
|
+
parser.add_argument("--scan", action="store_true", help="Scan the current project to prefill or auto-generate PROJECT_CONTEXT.md")
|
|
440
|
+
args = parser.parse_args()
|
|
284
441
|
|
|
285
442
|
print(f"""
|
|
286
|
-
{bold(cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'))}
|
|
287
|
-
{bold('thachvd-kit')} — Project Init Wizard
|
|
288
|
-
Generates PROJECT_CONTEXT.md for smart agent routing
|
|
289
|
-
{bold(cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'))}
|
|
290
|
-
""")
|
|
443
|
+
{bold(cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'))}
|
|
444
|
+
{bold('thachvd-kit')} — Project Init Wizard
|
|
445
|
+
Generates PROJECT_CONTEXT.md for smart agent routing{' (scan-assisted)' if args.scan else ''}
|
|
446
|
+
{bold(cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'))}
|
|
447
|
+
""")
|
|
291
448
|
|
|
292
449
|
# Check if PROJECT_CONTEXT.md already exists
|
|
293
450
|
output_path = Path("PROJECT_CONTEXT.md")
|
|
@@ -297,85 +454,118 @@ def main():
|
|
|
297
454
|
print(f"\n {yellow('Aborted.')} Existing PROJECT_CONTEXT.md unchanged.\n")
|
|
298
455
|
sys.exit(0)
|
|
299
456
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
457
|
+
use_scan = args.scan
|
|
458
|
+
if not args.scan and not args.yes:
|
|
459
|
+
section("Setup Mode")
|
|
460
|
+
project_setup = ask_select("Project already exists or are you starting fresh",
|
|
461
|
+
["existing", "new"], default="existing")
|
|
462
|
+
if project_setup == "existing":
|
|
463
|
+
existing_mode = ask_select("How should thachvd-kit build PROJECT_CONTEXT.md",
|
|
464
|
+
["scan", "manual"], default="scan")
|
|
465
|
+
use_scan = existing_mode == "scan"
|
|
466
|
+
|
|
467
|
+
scanned = scan_project() if use_scan else None
|
|
468
|
+
if use_scan:
|
|
469
|
+
print(f" {dim('Scan mode: detecting stack from current project files...')}")
|
|
470
|
+
print(f" {bold('Scan result:')} {scanned['primary_language']} | {', '.join(scanned['frameworks']) or 'no framework'}")
|
|
471
|
+
print(f" {bold('Detected infra:')} {', '.join(scanned['infrastructure']) or 'none'}\n")
|
|
472
|
+
elif not args.yes:
|
|
473
|
+
print(f" {dim('Manual mode: asking for project context explicitly.')}\n")
|
|
474
|
+
|
|
475
|
+
if args.yes and scanned:
|
|
476
|
+
data = dict(scanned)
|
|
477
|
+
else:
|
|
478
|
+
data = {}
|
|
479
|
+
|
|
480
|
+
if not args.yes:
|
|
481
|
+
# ── Project Info ──────────────────────────────────────────────────────
|
|
482
|
+
section("Project Info")
|
|
483
|
+
data["project_name"] = ask("Project name", default=(scanned or {}).get("project_name", Path.cwd().name))
|
|
484
|
+
data["description"] = ask("Short description", default=(scanned or {}).get("description", "A software project"))
|
|
485
|
+
data["project_type"] = ask("Project type",
|
|
486
|
+
default=(scanned or {}).get("project_type", "web-app"),
|
|
487
|
+
choices=PROJECT_TYPES_ALL)
|
|
488
|
+
|
|
489
|
+
# ── Tech Stack ────────────────────────────────────────────────────────
|
|
490
|
+
section("Tech Stack")
|
|
491
|
+
|
|
492
|
+
data["primary_language"] = ask("Primary language",
|
|
493
|
+
default=(scanned or {}).get("primary_language", "typescript"),
|
|
494
|
+
choices=LANGUAGES_ALL)
|
|
495
|
+
|
|
496
|
+
frameworks = ask_multi("Frameworks (select all that apply)", FRAMEWORKS_ALL, default=", ".join((scanned or {}).get("frameworks", [])) or None)
|
|
497
|
+
data["frameworks"] = frameworks or []
|
|
498
|
+
|
|
499
|
+
data["database"] = ask("Database / ORM", default=(scanned or {}).get("database", "postgres"), choices=DATABASES_ALL)
|
|
500
|
+
|
|
501
|
+
data["package_manager"] = ask("Package manager", default=(scanned or {}).get("package_manager", "auto-detect"), choices=PACKAGE_MANAGERS_ALL)
|
|
502
|
+
|
|
503
|
+
# ── Infrastructure ────────────────────────────────────────────────────
|
|
504
|
+
section("Infrastructure")
|
|
505
|
+
|
|
506
|
+
data["uses_docker"] = ask_bool("Uses Docker / Docker Compose?", default=(scanned or {}).get("uses_docker", True))
|
|
507
|
+
cloud = ask("Cloud provider", default=(scanned or {}).get("cloud", "none"), choices=CLOUDS_ALL)
|
|
508
|
+
data["cloud"] = cloud
|
|
509
|
+
|
|
510
|
+
infrastructure = []
|
|
511
|
+
if data["uses_docker"]: infrastructure.append("docker")
|
|
512
|
+
if cloud != "none": infrastructure.append(cloud)
|
|
513
|
+
data["infrastructure"] = infrastructure
|
|
514
|
+
|
|
515
|
+
CI_CD = ["github-actions", "gitlab-ci", "circleci", "jenkins", "none"]
|
|
516
|
+
data["ci_cd"] = ask("CI/CD", default=(scanned or {}).get("ci_cd", "github-actions"), choices=CI_CD)
|
|
517
|
+
|
|
518
|
+
# ── Testing ───────────────────────────────────────────────────────────
|
|
519
|
+
section("Testing")
|
|
520
|
+
|
|
521
|
+
data["test_framework"] = ask("Test framework", default=(scanned or {}).get("test_framework", "auto-detect"), choices=TEST_FRAMEWORKS_ALL)
|
|
522
|
+
|
|
523
|
+
# ── Conventions ───────────────────────────────────────────────────────
|
|
524
|
+
section("Coding Conventions")
|
|
525
|
+
|
|
526
|
+
data["max_file_lines"] = ask("Max lines per file before splitting", default=(scanned or {}).get("max_file_lines", "300"))
|
|
527
|
+
data["code_style"] = ask("Code style / linter", default=(scanned or {}).get("code_style", "project-standard"),
|
|
528
|
+
choices=["eslint", "prettier", "ruff", "gofmt", "pint", "standard", "project-standard"])
|
|
529
|
+
|
|
530
|
+
# ── Optional fields ───────────────────────────────────────────────────
|
|
531
|
+
section("Architecture (Optional — press Enter to skip)")
|
|
532
|
+
|
|
533
|
+
data["architecture_notes"] = ask("Key architecture notes", default=(scanned or {}).get("architecture_notes", "<!-- Add notes -->"))
|
|
534
|
+
data["current_phase"] = ask("Current phase", default=(scanned or {}).get("current_phase", "Initial setup"))
|
|
535
|
+
data["next_phase"] = ask("Next planned phase", default=(scanned or {}).get("next_phase", "—"))
|
|
536
|
+
data["known_issues"] = ask("Known issues / tasks", default=(scanned or {}).get("known_issues", "<!-- None yet -->"))
|
|
537
|
+
|
|
538
|
+
data["project_name"] = data.get("project_name", (scanned or {}).get("project_name", Path.cwd().name))
|
|
539
|
+
data["description"] = data.get("description", (scanned or {}).get("description", "A software project"))
|
|
540
|
+
data["project_type"] = data.get("project_type", (scanned or {}).get("project_type", "web-app"))
|
|
541
|
+
data["primary_language"] = data.get("primary_language", (scanned or {}).get("primary_language", "typescript"))
|
|
542
|
+
data["frameworks"] = data.get("frameworks", (scanned or {}).get("frameworks", []))
|
|
543
|
+
data["database"] = data.get("database", (scanned or {}).get("database", "none"))
|
|
544
|
+
data["package_manager"] = data.get("package_manager", (scanned or {}).get("package_manager", "auto-detect"))
|
|
545
|
+
data["uses_docker"] = data.get("uses_docker", (scanned or {}).get("uses_docker", True))
|
|
546
|
+
data["cloud"] = data.get("cloud", (scanned or {}).get("cloud", "none"))
|
|
547
|
+
data["test_framework"] = data.get("test_framework", (scanned or {}).get("test_framework", "auto-detect"))
|
|
548
|
+
data["max_file_lines"] = data.get("max_file_lines", (scanned or {}).get("max_file_lines", "300"))
|
|
549
|
+
data["code_style"] = data.get("code_style", (scanned or {}).get("code_style", "project-standard"))
|
|
550
|
+
data["architecture_notes"] = data.get("architecture_notes", (scanned or {}).get("architecture_notes", "<!-- Add notes -->"))
|
|
551
|
+
data["current_phase"] = data.get("current_phase", (scanned or {}).get("current_phase", "Initial setup"))
|
|
552
|
+
data["next_phase"] = data.get("next_phase", (scanned or {}).get("next_phase", "—"))
|
|
553
|
+
data["known_issues"] = data.get("known_issues", (scanned or {}).get("known_issues", "<!-- None yet -->"))
|
|
554
|
+
data["infrastructure"] = []
|
|
555
|
+
if data["uses_docker"]: data["infrastructure"].append("docker")
|
|
556
|
+
if data["cloud"] != "none": data["infrastructure"].append(data["cloud"])
|
|
557
|
+
|
|
558
|
+
# ── Generate files ────────────────────────────────────────────────────
|
|
559
|
+
section("Generating Files")
|
|
370
560
|
|
|
371
561
|
# PROJECT_CONTEXT.md (always)
|
|
372
|
-
context_content = generate_project_context(data)
|
|
373
|
-
output_path.write_text(context_content, encoding="utf-8")
|
|
374
|
-
print(f" {green('✓')} {bold('PROJECT_CONTEXT.md')} generated")
|
|
375
|
-
|
|
376
|
-
# CLAUDE.md (for Claude Code / Codex)
|
|
377
|
-
if args.platform in ("claude", "all"):
|
|
378
|
-
claude_path = Path("CLAUDE.md")
|
|
562
|
+
context_content = generate_project_context(data)
|
|
563
|
+
output_path.write_text(context_content, encoding="utf-8")
|
|
564
|
+
print(f" {green('✓')} {bold('PROJECT_CONTEXT.md')} generated")
|
|
565
|
+
|
|
566
|
+
# CLAUDE.md (for Claude Code / Codex)
|
|
567
|
+
if args.platform in ("claude", "all"):
|
|
568
|
+
claude_path = Path("CLAUDE.md")
|
|
379
569
|
claude_path.write_text(generate_claude_md(data), encoding="utf-8")
|
|
380
570
|
print(f" {green('✓')} {bold('CLAUDE.md')} generated (Claude Code / Codex)")
|
|
381
571
|
|
|
@@ -388,16 +578,21 @@ def main():
|
|
|
388
578
|
{bold('Stack:')} {data['primary_language']} | {', '.join(data['frameworks']) or 'no framework'}
|
|
389
579
|
{bold('Infra:')} {', '.join(data['infrastructure']) or 'none'}
|
|
390
580
|
|
|
391
|
-
{bold('Auto-resolved skills:')}
|
|
392
|
-
{chr(10).join(f' · {s}' for s in auto_skills)}
|
|
393
|
-
|
|
394
|
-
{bold('
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
{
|
|
400
|
-
|
|
581
|
+
{bold('Auto-resolved skills:')}
|
|
582
|
+
{chr(10).join(f' · {s}' for s in auto_skills)}
|
|
583
|
+
|
|
584
|
+
{bold('Generated files:')}
|
|
585
|
+
· {bold(str(output_path.resolve()))}
|
|
586
|
+
· {bold(str(Path("CLAUDE.md").resolve())) if args.platform in ("claude", "all") else 'CLAUDE.md not generated for this platform'}
|
|
587
|
+
|
|
588
|
+
{bold('Next steps:')}
|
|
589
|
+
1. Review {bold('PROJECT_CONTEXT.md')} first and add architecture notes
|
|
590
|
+
2. Instruct the agent to read/update {bold('PROJECT_CONTEXT.md')} before major tasks
|
|
591
|
+
3. Open project in your AI editor (Antigravity / Claude Code / Codex)
|
|
592
|
+
4. The agent will read PROJECT_CONTEXT.md on session start
|
|
593
|
+
|
|
594
|
+
{dim(' Tip: Run with --platform all to also generate CLAUDE.md')}
|
|
595
|
+
""")
|
|
401
596
|
|
|
402
597
|
if __name__ == "__main__":
|
|
403
598
|
main()
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: desktop-design
|
|
3
|
+
description: Desktop and cross-platform app design guidance for Tauri and similar desktop shells. Use when building desktop-first interfaces, windowed workflows, keyboard-heavy UX, or cross-platform desktop UI behavior.
|
|
4
|
+
allowed-tools: Read, Write, Edit, Glob, Grep, Bash
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Desktop Design
|
|
8
|
+
|
|
9
|
+
This skill covers desktop-first product thinking where `mobile-design` is the wrong default.
|
|
10
|
+
|
|
11
|
+
Use it for Tauri and other desktop-oriented apps with window management, keyboard shortcuts, dense layouts, or multi-panel workflows.
|
|
12
|
+
|
|
13
|
+
## Guidance
|
|
14
|
+
|
|
15
|
+
- Design for pointer + keyboard, not touch-first.
|
|
16
|
+
- Use information density deliberately; desktop screens can support richer sidebars and multi-column layouts.
|
|
17
|
+
- Respect platform conventions for menus, shortcuts, dialogs, file pickers, and drag/drop.
|
|
18
|
+
- Assume resizing, multiple windows, and long-running sessions are normal.
|
|
19
|
+
- Pair with `rust-pro` for Tauri backend/native concerns and `frontend-design` for UI execution.
|
|
20
|
+
|
|
21
|
+
## Related Skills
|
|
22
|
+
|
|
23
|
+
- `mobile-design` for touch-first mobile products
|
|
24
|
+
- `frontend-design` for visual and interaction design
|
|
25
|
+
- `rust-pro` for Rust and Tauri implementation details
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: react-frontend
|
|
3
|
+
description: React-focused frontend guidance for component architecture, state flow, rendering boundaries, and maintainable UI systems. Use for plain React apps that are not specifically Next.js-first.
|
|
4
|
+
allowed-tools: Read, Write, Edit, Glob, Grep, Bash
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# React Frontend
|
|
8
|
+
|
|
9
|
+
This skill is the React-first counterpart to `nextjs-react-expert`.
|
|
10
|
+
|
|
11
|
+
Use it when the project uses React without needing Next.js-specific assumptions such as SSR, App Router, or server components.
|
|
12
|
+
|
|
13
|
+
## Guidance
|
|
14
|
+
|
|
15
|
+
- Prefer the existing project architecture over introducing a new pattern.
|
|
16
|
+
- Keep state ownership shallow and explicit.
|
|
17
|
+
- Separate presentational UI from data-fetching and side effects when it improves maintainability.
|
|
18
|
+
- Optimize rendering only after confirming an actual bottleneck.
|
|
19
|
+
- Pair with `frontend-design` for UI/UX decisions.
|
|
20
|
+
|
|
21
|
+
## Related Skills
|
|
22
|
+
|
|
23
|
+
- `nextjs-react-expert` for Next.js-specific performance and routing concerns
|
|
24
|
+
- `frontend-design` for layout, visual hierarchy, and responsive design
|
|
25
|
+
- `clean-code` for naming, file boundaries, and readability
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
No,Data Type,Keywords,Best Chart Type,Secondary Options,Color Guidance,Performance Impact,Accessibility Notes,Library Recommendation,Interactive Level
|
|
2
|
-
1,Trend Over Time,"trend, time-series, line, growth, timeline, progress",Line Chart,"Area Chart, Smooth Area",Primary: #0080FF. Multiple series: use distinct colors. Fill: 20% opacity,⚡ Excellent (optimized),✓ Clear line patterns for colorblind users. Add pattern overlays.,"Chart.js, Recharts, ApexCharts",Hover + Zoom
|
|
3
|
-
2,Compare Categories,"compare, categories, bar, comparison, ranking",Bar Chart (Horizontal or Vertical),"Column Chart, Grouped Bar",Each bar: distinct color. Category: grouped same color. Sorted: descending order,⚡ Excellent,✓ Easy to compare. Add value labels on bars for clarity.,"Chart.js, Recharts, D3.js",Hover + Sort
|
|
4
|
-
3,Part-to-Whole,"part-to-whole, pie, donut, percentage, proportion, share",Pie Chart or Donut,"Stacked Bar, Treemap",Colors: 5-6 max. Contrasting palette. Large slices first. Use labels.,⚡ Good (limit 6 slices),⚠ Hard for accessibility. Better: Stacked bar with legend. Avoid pie if >5 items.,"Chart.js, Recharts, D3.js",Hover + Drill
|
|
5
|
-
4,Correlation/Distribution,"correlation, distribution, scatter, relationship, pattern",Scatter Plot or Bubble Chart,"Heat Map, Matrix",Color axis: gradient (blue-red). Size: relative. Opacity: 0.6-0.8 to show density,⚠ Moderate (many points),⚠ Provide data table alternative. Use pattern + color distinction.,"D3.js, Plotly, Recharts",Hover + Brush
|
|
6
|
-
5,Heatmap/Intensity,"heatmap, heat-map, intensity, density, matrix",Heat Map or Choropleth,"Grid Heat Map, Bubble Heat",Gradient: Cool (blue) to Hot (red). Scale: clear legend. Divergent for ±data,⚡ Excellent (color CSS),⚠ Colorblind: Use pattern overlay. Provide numerical legend.,"D3.js, Plotly, ApexCharts",Hover + Zoom
|
|
7
|
-
6,Geographic Data,"geographic, map, location, region, geo, spatial","Choropleth Map, Bubble Map",Geographic Heat Map,Regional: single color gradient or categorized colors. Legend: clear scale,⚠ Moderate (rendering),⚠ Include text labels for regions. Provide data table alternative.,"D3.js, Mapbox, Leaflet",Pan + Zoom + Drill
|
|
8
|
-
7,Funnel/Flow,funnel/flow,"Funnel Chart, Sankey",Waterfall (for flows),Stages: gradient (starting color → ending color). Show conversion %,⚡ Good,✓ Clear stage labels + percentages. Good for accessibility if labeled.,"D3.js, Recharts, Custom SVG",Hover + Drill
|
|
9
|
-
8,Performance vs Target,performance-vs-target,Gauge Chart or Bullet Chart,"Dial, Thermometer",Performance: Red→Yellow→Green gradient. Target: marker line. Threshold colors,⚡ Good,✓ Add numerical value + percentage label beside gauge.,"D3.js, ApexCharts, Custom SVG",Hover
|
|
10
|
-
9,Time-Series Forecast,time-series-forecast,Line with Confidence Band,Ribbon Chart,Actual: solid line #0080FF. Forecast: dashed #FF9500. Band: light shading,⚡ Good,✓ Clearly distinguish actual vs forecast. Add legend.,"Chart.js, ApexCharts, Plotly",Hover + Toggle
|
|
11
|
-
10,Anomaly Detection,anomaly-detection,Line Chart with Highlights,Scatter with Alert,Normal: blue #0080FF. Anomaly: red #FF0000 circle/square marker + alert,⚡ Good,✓ Circle/marker for anomalies. Add text alert annotation.,"D3.js, Plotly, ApexCharts",Hover + Alert
|
|
12
|
-
11,Hierarchical/Nested Data,hierarchical/nested-data,Treemap,"Sunburst, Nested Donut, Icicle",Parent: distinct hues. Children: lighter shades. White borders 2-3px.,⚠ Moderate,⚠ Poor - provide table alternative. Label large areas.,"D3.js, Recharts, ApexCharts",Hover + Drilldown
|
|
13
|
-
12,Flow/Process Data,flow/process-data,Sankey Diagram,"Alluvial, Chord Diagram",Gradient from source to target. Opacity 0.4-0.6 for flows.,⚠ Moderate,⚠ Poor - provide flow table alternative.,"D3.js (d3-sankey), Plotly",Hover + Drilldown
|
|
14
|
-
13,Cumulative Changes,cumulative-changes,Waterfall Chart,"Stacked Bar, Cascade",Increases: #4CAF50. Decreases: #F44336. Start: #2196F3. End: #0D47A1.,⚡ Good,✓ Good - clear directional colors with labels.,"ApexCharts, Highcharts, Plotly",Hover
|
|
15
|
-
14,Multi-Variable Comparison,multi-variable-comparison,Radar/Spider Chart,"Parallel Coordinates, Grouped Bar",Single: #0080FF 20% fill. Multiple: distinct colors per dataset.,⚡ Good,⚠ Moderate - limit 5-8 axes. Add data table.,"Chart.js, Recharts, ApexCharts",Hover + Toggle
|
|
16
|
-
15,Stock/Trading OHLC,stock/trading-ohlc,Candlestick Chart,"OHLC Bar, Heikin-Ashi",Bullish: #26A69A. Bearish: #EF5350. Volume: 40% opacity below.,⚡ Good,⚠ Moderate - provide OHLC data table.,"Lightweight Charts (TradingView), ApexCharts",Real-time + Hover + Zoom
|
|
17
|
-
16,Relationship/Connection Data,relationship/connection-data,Network Graph,"Hierarchical Tree, Adjacency Matrix",Node types: categorical colors. Edges: #90A4AE 60% opacity.,❌ Poor (500+ nodes struggles),❌ Very Poor - provide adjacency list alternative.,"D3.js (d3-force), Vis.js, Cytoscape.js",Drilldown + Hover + Drag
|
|
18
|
-
17,Distribution/Statistical,distribution/statistical,Box Plot,"Violin Plot, Beeswarm",Box: #BBDEFB. Border: #1976D2. Median: #D32F2F. Outliers: #F44336.,⚡ Excellent,"✓ Good - include stats table (min, Q1, median, Q3, max).","Plotly, D3.js, Chart.js (plugin)",Hover
|
|
19
|
-
18,Performance vs Target (Compact),performance-vs-target-(compact),Bullet Chart,"Gauge, Progress Bar","Ranges: #FFCDD2, #FFF9C4, #C8E6C9. Performance: #1976D2. Target: black 3px.",⚡ Excellent,✓ Excellent - compact with clear values.,"D3.js, Plotly, Custom SVG",Hover
|
|
20
|
-
19,Proportional/Percentage,proportional/percentage,Waffle Chart,"Pictogram, Stacked Bar 100%",10x10 grid. 3-5 categories max. 2-3px spacing between squares.,⚡ Good,✓ Good - better than pie for accessibility.,"D3.js, React-Waffle, Custom CSS Grid",Hover
|
|
21
|
-
20,Hierarchical Proportional,hierarchical-proportional,Sunburst Chart,"Treemap, Icicle, Circle Packing",Center to outer: darker to lighter. 15-20% lighter per level.,⚠ Moderate,⚠ Poor - provide hierarchy table alternative.,"D3.js (d3-hierarchy), Recharts, ApexCharts",Drilldown + Hover
|
|
22
|
-
21,Root Cause Analysis,"root cause, decomposition, tree, hierarchy, drill-down, ai-split",Decomposition Tree,"Decision Tree, Flow Chart",Nodes: #2563EB (Primary) vs #EF4444 (Negative impact). Connectors: Neutral grey.,⚠ Moderate (calculation heavy),✓ clear hierarchy. Allow keyboard navigation for nodes.,"Power BI (native), React-Flow, Custom D3.js",Drill + Expand
|
|
23
|
-
22,3D Spatial Data,"3d, spatial, immersive, terrain, molecular, volumetric",3D Scatter/Surface Plot,"Volumetric Rendering, Point Cloud",Depth cues: lighting/shading. Z-axis: color gradient (cool to warm).,❌ Heavy (WebGL required),❌ Poor - requires alternative 2D view or data table.,"Three.js, Deck.gl, Plotly 3D",Rotate + Zoom + VR
|
|
24
|
-
23,Real-Time Streaming,"streaming, real-time, ticker, live, velocity, pulse",Streaming Area Chart,"Ticker Tape, Moving Gauge",Current: Bright Pulse (#00FF00). History: Fading opacity. Grid: Dark.,⚡ Optimized (canvas/webgl),⚠ Flashing elements - provide pause button. High contrast.,Smoothed D3.js, CanvasJS, SciChart,Real-time + Pause
|
|
25
|
-
24,Sentiment/Emotion,"sentiment, emotion, nlp, opinion, feeling",Word Cloud with Sentiment,"Sentiment Arc, Radar Chart",Positive: #22C55E. Negative: #EF4444. Neutral: #94A3B8. Size = Frequency.,⚡ Good,⚠ Word clouds poor for screen readers. Use list view.,"D3-cloud, Highcharts, Nivo",Hover + Filter
|
|
26
|
-
25,Process Mining,"process, mining, variants, path, bottleneck, log",Process Map / Graph,"Directed Acyclic Graph (DAG), Petri Net",Happy path: #10B981 (Thick). Deviations: #F59E0B (Thin). Bottlenecks: #EF4444.,⚠ Moderate to Heavy,⚠ Complex graphs hard to navigate. Provide path summary.,"React-Flow, Cytoscape.js, Recharts",Drag + Node-Click
|