@kkelly-offical/kkcode 0.1.3 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +110 -172
  2. package/package.json +46 -46
  3. package/src/agent/agent.mjs +220 -170
  4. package/src/agent/prompt/bug-hunter.txt +90 -0
  5. package/src/agent/prompt/frontend-designer.txt +58 -0
  6. package/src/agent/prompt/longagent-blueprint-agent.txt +83 -0
  7. package/src/agent/prompt/longagent-coding-agent.txt +37 -0
  8. package/src/agent/prompt/longagent-debugging-agent.txt +46 -0
  9. package/src/agent/prompt/longagent-preview-agent.txt +63 -0
  10. package/src/config/defaults.mjs +260 -195
  11. package/src/config/schema.mjs +71 -6
  12. package/src/core/constants.mjs +91 -46
  13. package/src/index.mjs +1 -1
  14. package/src/knowledge/frontend-aesthetics.txt +39 -0
  15. package/src/knowledge/loader.mjs +2 -1
  16. package/src/knowledge/tailwind.txt +12 -3
  17. package/src/mcp/client-http.mjs +141 -157
  18. package/src/mcp/client-sse.mjs +288 -286
  19. package/src/mcp/client-stdio.mjs +533 -451
  20. package/src/mcp/constants.mjs +2 -0
  21. package/src/mcp/registry.mjs +479 -394
  22. package/src/mcp/stdio-framing.mjs +133 -127
  23. package/src/mcp/tool-result.mjs +24 -0
  24. package/src/observability/index.mjs +42 -0
  25. package/src/observability/metrics.mjs +137 -0
  26. package/src/observability/tracer.mjs +137 -0
  27. package/src/orchestration/background-manager.mjs +372 -358
  28. package/src/orchestration/background-worker.mjs +305 -245
  29. package/src/orchestration/longagent-manager.mjs +171 -116
  30. package/src/orchestration/stage-scheduler.mjs +728 -489
  31. package/src/permission/exec-policy.mjs +9 -11
  32. package/src/provider/anthropic.mjs +1 -0
  33. package/src/provider/openai.mjs +340 -339
  34. package/src/provider/retry-policy.mjs +68 -68
  35. package/src/provider/router.mjs +241 -228
  36. package/src/provider/sse.mjs +104 -91
  37. package/src/repl.mjs +59 -7
  38. package/src/session/checkpoint.mjs +66 -3
  39. package/src/session/compaction.mjs +298 -276
  40. package/src/session/engine.mjs +232 -225
  41. package/src/session/longagent-4stage.mjs +460 -0
  42. package/src/session/longagent-hybrid.mjs +1097 -0
  43. package/src/session/longagent-plan.mjs +365 -329
  44. package/src/session/longagent-project-memory.mjs +53 -0
  45. package/src/session/longagent-scaffold.mjs +291 -100
  46. package/src/session/longagent-task-bus.mjs +54 -0
  47. package/src/session/longagent-utils.mjs +472 -0
  48. package/src/session/longagent.mjs +900 -1462
  49. package/src/session/loop.mjs +65 -40
  50. package/src/session/project-context.mjs +30 -0
  51. package/src/session/prompt/agent.txt +25 -0
  52. package/src/session/prompt/plan.txt +31 -9
  53. package/src/session/rollback.mjs +196 -0
  54. package/src/session/store.mjs +519 -503
  55. package/src/session/system-prompt.mjs +273 -260
  56. package/src/session/task-validator.mjs +4 -3
  57. package/src/skill/builtin/design.mjs +76 -0
  58. package/src/skill/builtin/frontend.mjs +8 -0
  59. package/src/skill/registry.mjs +390 -336
  60. package/src/storage/ghost-commit-store.mjs +18 -8
  61. package/src/tool/executor.mjs +11 -0
  62. package/src/tool/git-auto.mjs +0 -19
  63. package/src/tool/question-prompt.mjs +93 -86
  64. package/src/tool/registry.mjs +71 -37
  65. package/src/ui/activity-renderer.mjs +664 -410
  66. package/src/util/git.mjs +23 -0
@@ -39,11 +39,10 @@ export function validateConfig(config) {
39
39
  err(errors, "provider", "must be object")
40
40
  } else {
41
41
  const providerTypes = getValidProviderTypes()
42
- const knownKeys = new Set([...providerTypes, ...Object.keys(config.provider).filter(k => k !== "default")])
43
- if (config.provider.default !== undefined && !knownKeys.has(config.provider.default)) {
44
- err(errors, "provider.default", `must be one of ${[...knownKeys].join(", ")}`)
45
- }
46
42
  const providerKeys = new Set([...providerTypes, ...Object.keys(config.provider).filter(k => k !== "default")])
43
+ if (config.provider.default !== undefined && !providerKeys.has(config.provider.default)) {
44
+ err(errors, "provider.default", `must be one of ${[...providerKeys].join(", ")}`)
45
+ }
47
46
  for (const key of providerKeys) {
48
47
  const p = config.provider[key]
49
48
  if (p === undefined) continue
@@ -72,6 +71,9 @@ export function validateConfig(config) {
72
71
  }
73
72
  }
74
73
  }
74
+ if (config.provider.strict_mode !== undefined && typeof config.provider.strict_mode !== "boolean") {
75
+ err(errors, "provider.strict_mode", "must be boolean")
76
+ }
75
77
  if (config.provider.model_context !== undefined) {
76
78
  if (!isObj(config.provider.model_context)) err(errors, "provider.model_context", "must be object")
77
79
  else {
@@ -118,8 +120,11 @@ export function validateConfig(config) {
118
120
  if (config.agent.longagent.parallel.max_concurrency !== undefined) {
119
121
  checkInt(errors, "agent.longagent.parallel.max_concurrency", config.agent.longagent.parallel.max_concurrency, 1)
120
122
  }
121
- if (config.agent.longagent.parallel.stage_pass_rule !== undefined && config.agent.longagent.parallel.stage_pass_rule !== "all_success") {
122
- err(errors, "agent.longagent.parallel.stage_pass_rule", "must be all_success")
123
+ if (config.agent.longagent.parallel.stage_pass_rule !== undefined && !["all_success", "majority", "any_success"].includes(config.agent.longagent.parallel.stage_pass_rule)) {
124
+ err(errors, "agent.longagent.parallel.stage_pass_rule", "must be all_success|majority|any_success")
125
+ }
126
+ if (config.agent.longagent.parallel.poll_interval_ms !== undefined) {
127
+ checkInt(errors, "agent.longagent.parallel.poll_interval_ms", config.agent.longagent.parallel.poll_interval_ms, 50)
123
128
  }
124
129
  if (config.agent.longagent.parallel.task_timeout_ms !== undefined) {
125
130
  checkInt(errors, "agent.longagent.parallel.task_timeout_ms", config.agent.longagent.parallel.task_timeout_ms, 1000)
@@ -150,6 +155,58 @@ export function validateConfig(config) {
150
155
  }
151
156
  }
152
157
  }
158
+ if (config.agent.longagent.lock_timeout_ms !== undefined) {
159
+ checkInt(errors, "agent.longagent.lock_timeout_ms", config.agent.longagent.lock_timeout_ms, 1000)
160
+ }
161
+ if (config.agent.longagent.four_stage !== undefined) {
162
+ if (!isObj(config.agent.longagent.four_stage)) {
163
+ err(errors, "agent.longagent.four_stage", "must be object")
164
+ } else {
165
+ const fs = config.agent.longagent.four_stage
166
+ if (fs.enabled !== undefined && typeof fs.enabled !== "boolean") err(errors, "agent.longagent.four_stage.enabled", "must be boolean")
167
+ if (fs.separate_models !== undefined) {
168
+ if (!isObj(fs.separate_models)) err(errors, "agent.longagent.four_stage.separate_models", "must be object")
169
+ else {
170
+ if (fs.separate_models.enabled !== undefined && typeof fs.separate_models.enabled !== "boolean") err(errors, "agent.longagent.four_stage.separate_models.enabled", "must be boolean")
171
+ for (const k of ["preview_model", "blueprint_model", "coding_model", "debugging_model"]) {
172
+ if (fs.separate_models[k] !== undefined && fs.separate_models[k] !== null && typeof fs.separate_models[k] !== "string") {
173
+ err(errors, `agent.longagent.four_stage.separate_models.${k}`, "must be string or null")
174
+ }
175
+ }
176
+ }
177
+ }
178
+ }
179
+ }
180
+ if (config.agent.longagent.hybrid !== undefined) {
181
+ if (!isObj(config.agent.longagent.hybrid)) {
182
+ err(errors, "agent.longagent.hybrid", "must be object")
183
+ } else {
184
+ const hy = config.agent.longagent.hybrid
185
+ if (hy.enabled !== undefined && typeof hy.enabled !== "boolean") err(errors, "agent.longagent.hybrid.enabled", "must be boolean")
186
+ if (hy.separate_models !== undefined) {
187
+ if (!isObj(hy.separate_models)) err(errors, "agent.longagent.hybrid.separate_models", "must be object")
188
+ else {
189
+ if (hy.separate_models.enabled !== undefined && typeof hy.separate_models.enabled !== "boolean") err(errors, "agent.longagent.hybrid.separate_models.enabled", "must be boolean")
190
+ for (const k of ["preview_model", "blueprint_model", "debugging_model"]) {
191
+ if (hy.separate_models[k] !== undefined && hy.separate_models[k] !== null && typeof hy.separate_models[k] !== "string") {
192
+ err(errors, `agent.longagent.hybrid.separate_models.${k}`, "must be string or null")
193
+ }
194
+ }
195
+ }
196
+ }
197
+ if (hy.adaptive_models !== undefined) {
198
+ if (!isObj(hy.adaptive_models)) err(errors, "agent.longagent.hybrid.adaptive_models", "must be object")
199
+ else {
200
+ if (hy.adaptive_models.enabled !== undefined && typeof hy.adaptive_models.enabled !== "boolean") err(errors, "agent.longagent.hybrid.adaptive_models.enabled", "must be boolean")
201
+ for (const k of ["low", "medium", "high"]) {
202
+ if (hy.adaptive_models[k] !== undefined && hy.adaptive_models[k] !== null && typeof hy.adaptive_models[k] !== "string") {
203
+ err(errors, `agent.longagent.hybrid.adaptive_models.${k}`, "must be string or null")
204
+ }
205
+ }
206
+ }
207
+ }
208
+ }
209
+ }
153
210
  if (config.agent.longagent.resume_incomplete_files !== undefined && typeof config.agent.longagent.resume_incomplete_files !== "boolean") {
154
211
  err(errors, "agent.longagent.resume_incomplete_files", "must be boolean")
155
212
  }
@@ -180,6 +237,8 @@ export function validateConfig(config) {
180
237
  else {
181
238
  if (config.mcp.servers !== undefined && !isObj(config.mcp.servers)) err(errors, "mcp.servers", "must be object")
182
239
  if (config.mcp.timeout_ms !== undefined) checkInt(errors, "mcp.timeout_ms", config.mcp.timeout_ms, 1000)
240
+ if (config.mcp.shutdown_timeout_ms !== undefined) checkInt(errors, "mcp.shutdown_timeout_ms", config.mcp.shutdown_timeout_ms, 100)
241
+ if (config.mcp.max_sse_buffer_bytes !== undefined) checkInt(errors, "mcp.max_sse_buffer_bytes", config.mcp.max_sse_buffer_bytes, 1024)
183
242
  if (config.mcp.auto_discover !== undefined && typeof config.mcp.auto_discover !== "boolean") {
184
243
  err(errors, "mcp.auto_discover", "must be boolean")
185
244
  }
@@ -249,6 +308,10 @@ export function validateConfig(config) {
249
308
  if (config.skills.dirs !== undefined && !Array.isArray(config.skills.dirs)) {
250
309
  err(errors, "skills.dirs", "must be array")
251
310
  }
311
+ if (config.skills.allowed_commands !== undefined) {
312
+ if (!Array.isArray(config.skills.allowed_commands)) err(errors, "skills.allowed_commands", "must be array")
313
+ else if (config.skills.allowed_commands.some(c => typeof c !== "string")) err(errors, "skills.allowed_commands", "all values must be string")
314
+ }
252
315
  }
253
316
  }
254
317
 
@@ -325,6 +388,7 @@ export function validateConfig(config) {
325
388
  }
326
389
  if (config.background.worker_timeout_ms !== undefined) checkInt(errors, "background.worker_timeout_ms", config.background.worker_timeout_ms, 1000)
327
390
  if (config.background.max_parallel !== undefined) checkInt(errors, "background.max_parallel", config.background.max_parallel, 1)
391
+ if (config.background.max_log_lines !== undefined) checkInt(errors, "background.max_log_lines", config.background.max_log_lines, 1)
328
392
  }
329
393
  }
330
394
 
@@ -357,6 +421,7 @@ export function validateConfig(config) {
357
421
  }
358
422
  if (config.tool.local_dirs !== undefined && !Array.isArray(config.tool.local_dirs)) err(errors, "tool.local_dirs", "must be array")
359
423
  if (config.tool.plugin_dirs !== undefined && !Array.isArray(config.tool.plugin_dirs)) err(errors, "tool.plugin_dirs", "must be array")
424
+ if (config.tool.bash_timeout_ms !== undefined) checkInt(errors, "tool.bash_timeout_ms", config.tool.bash_timeout_ms, 1000)
360
425
  }
361
426
  }
362
427
 
@@ -1,46 +1,91 @@
1
- export const MODES = ["ask", "plan", "agent", "longagent"]
2
-
3
- export const TOOL_STATUSES = ["running", "completed", "error", "cancelled"]
4
-
5
- export const PERMISSION_DECISIONS = ["allow_once", "allow_session", "deny"]
6
-
7
- export const DEFAULT_MAX_STEPS = 8
8
- export const DEFAULT_REQUEST_TIMEOUT_MS = 120000
9
- export const DEFAULT_RETRY_ATTEMPTS = 3
10
- export const DEFAULT_LONGAGENT_RETRY_STORM_THRESHOLD = 3
11
- export const DEFAULT_LONGAGENT_TOKEN_ALERT_THRESHOLD = 120000
12
-
13
- export const EVENT_TYPES = {
14
- TURN_START: "turn.start",
15
- TURN_STEP_START: "turn.step.start",
16
- TURN_STEP_FINISH: "turn.step.finish",
17
- TURN_FINISH: "turn.finish",
18
- TURN_ERROR: "turn.error",
19
- TOOL_START: "tool.start",
20
- TOOL_FINISH: "tool.finish",
21
- TOOL_ERROR: "tool.error",
22
- PERMISSION_ASKED: "permission.asked",
23
- PERMISSION_DECIDED: "permission.decided",
24
- REVIEW_DECISION: "review.decision",
25
- MCP_HEALTH: "mcp.health",
26
- MCP_REQUEST: "mcp.request",
27
- LONGAGENT_HEARTBEAT: "longagent.heartbeat",
28
- LONGAGENT_ALERT: "longagent.alert",
29
- LONGAGENT_PHASE_CHANGED: "longagent.phase.changed",
30
- LONGAGENT_GATE_CHECKED: "longagent.gate.checked",
31
- LONGAGENT_RECOVERY_ENTERED: "longagent.recovery.entered",
32
- LONGAGENT_INTAKE_STARTED: "longagent.intake.started",
33
- LONGAGENT_PLAN_FROZEN: "longagent.plan.frozen",
34
- LONGAGENT_STAGE_STARTED: "longagent.stage.started",
35
- LONGAGENT_STAGE_TASK_DISPATCHED: "longagent.stage.task.dispatched",
36
- LONGAGENT_STAGE_TASK_FINISHED: "longagent.stage.task.finished",
37
- LONGAGENT_STAGE_FINISHED: "longagent.stage.finished",
38
- LONGAGENT_SCAFFOLD_COMPLETE: "longagent.scaffold.complete",
39
- LONGAGENT_GIT_BRANCH_CREATED: "longagent.git.branch.created",
40
- LONGAGENT_GIT_STAGE_COMMITTED: "longagent.git.stage.committed",
41
- LONGAGENT_GIT_MERGED: "longagent.git.merged",
42
- SESSION_COMPACTED: "session.compacted",
43
- TURN_USAGE_UPDATE: "turn.usage.update",
44
- STREAM_TEXT_START: "stream.text.start",
45
- STREAM_THINKING_START: "stream.thinking.start"
46
- }
1
+ export const MODES = ["ask", "plan", "agent", "longagent"]
2
+
3
+ export const TOOL_STATUSES = ["running", "completed", "error", "cancelled"]
4
+
5
+ export const PERMISSION_DECISIONS = ["allow_once", "allow_session", "deny"]
6
+
7
+ export const DEFAULT_MAX_STEPS = 8
8
+ export const DEFAULT_REQUEST_TIMEOUT_MS = 120000
9
+ export const DEFAULT_RETRY_ATTEMPTS = 3
10
+ export const DEFAULT_LONGAGENT_RETRY_STORM_THRESHOLD = 3
11
+ export const DEFAULT_LONGAGENT_TOKEN_ALERT_THRESHOLD = 120000
12
+
13
+ export const LONGAGENT_4STAGE_STAGES = {
14
+ PREVIEW: "preview",
15
+ BLUEPRINT: "blueprint",
16
+ CODING: "coding",
17
+ DEBUGGING: "debugging"
18
+ }
19
+
20
+ export const EVENT_TYPES = {
21
+ TURN_START: "turn.start",
22
+ TURN_STEP_START: "turn.step.start",
23
+ TURN_STEP_FINISH: "turn.step.finish",
24
+ TURN_FINISH: "turn.finish",
25
+ TURN_ERROR: "turn.error",
26
+ TOOL_START: "tool.start",
27
+ TOOL_FINISH: "tool.finish",
28
+ TOOL_ERROR: "tool.error",
29
+ PERMISSION_ASKED: "permission.asked",
30
+ PERMISSION_DECIDED: "permission.decided",
31
+ REVIEW_DECISION: "review.decision",
32
+ MCP_HEALTH: "mcp.health",
33
+ MCP_REQUEST: "mcp.request",
34
+ MCP_RECONNECT: "mcp.reconnect",
35
+ MCP_CIRCUIT_OPEN: "mcp.circuit_open",
36
+ MCP_CIRCUIT_CLOSE: "mcp.circuit_close",
37
+ LONGAGENT_HEARTBEAT: "longagent.heartbeat",
38
+ LONGAGENT_ALERT: "longagent.alert",
39
+ LONGAGENT_PHASE_CHANGED: "longagent.phase.changed",
40
+ LONGAGENT_GATE_CHECKED: "longagent.gate.checked",
41
+ LONGAGENT_RECOVERY_ENTERED: "longagent.recovery.entered",
42
+ LONGAGENT_INTAKE_STARTED: "longagent.intake.started",
43
+ LONGAGENT_PLAN_FROZEN: "longagent.plan.frozen",
44
+ LONGAGENT_STAGE_STARTED: "longagent.stage.started",
45
+ LONGAGENT_STAGE_TASK_DISPATCHED: "longagent.stage.task.dispatched",
46
+ LONGAGENT_STAGE_TASK_FINISHED: "longagent.stage.task.finished",
47
+ LONGAGENT_STAGE_FINISHED: "longagent.stage.finished",
48
+ LONGAGENT_SCAFFOLD_COMPLETE: "longagent.scaffold.complete",
49
+ LONGAGENT_GIT_BRANCH_CREATED: "longagent.git.branch.created",
50
+ LONGAGENT_GIT_STAGE_COMMITTED: "longagent.git.stage.committed",
51
+ LONGAGENT_GIT_MERGED: "longagent.git.merged",
52
+ LONGAGENT_4STAGE_PREVIEW_START: "longagent.4stage.preview.start",
53
+ LONGAGENT_4STAGE_PREVIEW_COMPLETE: "longagent.4stage.preview.complete",
54
+ LONGAGENT_4STAGE_BLUEPRINT_START: "longagent.4stage.blueprint.start",
55
+ LONGAGENT_4STAGE_BLUEPRINT_COMPLETE: "longagent.4stage.blueprint.complete",
56
+ LONGAGENT_4STAGE_CODING_START: "longagent.4stage.coding.start",
57
+ LONGAGENT_4STAGE_CODING_COMPLETE: "longagent.4stage.coding.complete",
58
+ LONGAGENT_4STAGE_DEBUGGING_START: "longagent.4stage.debugging.start",
59
+ LONGAGENT_4STAGE_DEBUGGING_COMPLETE: "longagent.4stage.debugging.complete",
60
+ LONGAGENT_4STAGE_RETURN_TO_CODING: "longagent.4stage.return_to_coding",
61
+ LONGAGENT_HYBRID_PREVIEW_START: "longagent.hybrid.preview.start",
62
+ LONGAGENT_HYBRID_PREVIEW_COMPLETE: "longagent.hybrid.preview.complete",
63
+ LONGAGENT_HYBRID_BLUEPRINT_START: "longagent.hybrid.blueprint.start",
64
+ LONGAGENT_HYBRID_BLUEPRINT_COMPLETE: "longagent.hybrid.blueprint.complete",
65
+ LONGAGENT_HYBRID_DEBUGGING_START: "longagent.hybrid.debugging.start",
66
+ LONGAGENT_HYBRID_DEBUGGING_COMPLETE: "longagent.hybrid.debugging.complete",
67
+ LONGAGENT_HYBRID_RETURN_TO_CODING: "longagent.hybrid.return_to_coding",
68
+ LONGAGENT_HYBRID_BLUEPRINT_REVIEW: "longagent.hybrid.blueprint.review",
69
+ LONGAGENT_HYBRID_BLUEPRINT_VALIDATED: "longagent.hybrid.blueprint.validated",
70
+ LONGAGENT_HYBRID_CROSS_REVIEW: "longagent.hybrid.cross_review",
71
+ LONGAGENT_HYBRID_INCREMENTAL_GATE: "longagent.hybrid.incremental_gate",
72
+ LONGAGENT_HYBRID_CONTEXT_COMPRESSED: "longagent.hybrid.context_compressed",
73
+ LONGAGENT_HYBRID_BUDGET_WARNING: "longagent.hybrid.budget_warning",
74
+ LONGAGENT_HYBRID_CHECKPOINT_RESUMED: "longagent.hybrid.checkpoint_resumed",
75
+ LONGAGENT_HYBRID_REPLAN: "longagent.hybrid.replan",
76
+ LONGAGENT_HYBRID_MEMORY_LOADED: "longagent.hybrid.memory_loaded",
77
+ LONGAGENT_HYBRID_MEMORY_SAVED: "longagent.hybrid.memory_saved",
78
+ SESSION_COMPACTED: "session.compacted",
79
+ TURN_USAGE_UPDATE: "turn.usage.update",
80
+ STREAM_TEXT_START: "stream.text.start",
81
+ STREAM_THINKING_START: "stream.thinking.start",
82
+ LONGAGENT_DEGRADATION_APPLIED: "longagent.degradation.applied",
83
+ LONGAGENT_WRITE_LOOP_DETECTED: "longagent.write_loop.detected",
84
+ LONGAGENT_SEMANTIC_ERROR_REPEATED: "longagent.semantic_error.repeated",
85
+ LONGAGENT_PHASE_TIMEOUT: "longagent.phase.timeout",
86
+ LONGAGENT_GIT_CONFLICT_RESOLUTION: "longagent.git.conflict_resolution",
87
+ LONGAGENT_CHECKPOINT_CLEANED: "longagent.checkpoint.cleaned",
88
+ LONGAGENT_HYBRID_CHECKPOINT_INVALID: "longagent.hybrid.checkpoint_invalid",
89
+ LONGAGENT_STAGE_TASK_SKIPPED: "longagent.stage.task.skipped",
90
+ PROVIDER_FALLBACK: "provider.fallback"
91
+ }
package/src/index.mjs CHANGED
@@ -54,7 +54,7 @@ async function main() {
54
54
  }
55
55
 
56
56
  const program = new Command()
57
- program.name("kkcode").description("kkcode CLI").version("0.1.3")
57
+ program.name("kkcode").description("kkcode CLI").version("0.1.6")
58
58
  program.addCommand(createChatCommand())
59
59
  program.addCommand(createThemeCommand())
60
60
  program.addCommand(createUsageCommand())
@@ -0,0 +1,39 @@
1
+ <frontend_aesthetics>
2
+ ## Frontend Design Quality Rules
3
+
4
+ When building frontend UI, avoid generic "AI-generated" aesthetics. Make creative, distinctive choices.
5
+
6
+ ### Typography
7
+ - Avoid default fonts (Inter, Roboto, Arial, system-ui). Choose distinctive fonts.
8
+ - Use high contrast: pair display fonts with monospace, serif with geometric sans.
9
+ - Use extreme weight differences (200 vs 800) and 3x+ size jumps.
10
+ - Load fonts from Google Fonts via <link> or @import.
11
+
12
+ ### Color
13
+ - Define ALL colors as CSS variables in :root.
14
+ - Use a dominant color with 1-2 sharp accents. Avoid evenly-distributed palettes.
15
+ - Draw from real palettes: IDE themes (Nord, Catppuccin, Dracula), nature, cultural aesthetics.
16
+ - AVOID: purple gradients on white, generic blue buttons, gray-on-gray cards.
17
+
18
+ ### Motion
19
+ - One high-impact animation per page (staggered reveal on load).
20
+ - Micro-interactions: hover lift, focus glow, press feedback.
21
+ - Use CSS transitions/animations. Use animation-delay for staggered effects.
22
+
23
+ ### Layout
24
+ - CSS Grid for page structure, Flexbox for components.
25
+ - Generous whitespace. Consistent spacing scale (4/8/12/16/24/32/48/64px).
26
+ - Mobile-first responsive design.
27
+
28
+ ### Depth & Atmosphere
29
+ - Layered gradients, subtle patterns, backdrop-filter for glass effects.
30
+ - Elevation hierarchy via box-shadow (not just border).
31
+ - Noise/grain textures for premium feel.
32
+
33
+ ### What NOT to do
34
+ - Cookie-cutter card grids with identical rounded corners
35
+ - Generic hero with centered text + gradient
36
+ - border-radius: 9999px on everything
37
+ - Gray placeholder text that looks like wireframe
38
+ - No visual rhythm (identical spacing everywhere)
39
+ </frontend_aesthetics>
@@ -58,7 +58,8 @@ const LANGUAGE_MAP = {
58
58
  // Project type → scenario knowledge
59
59
  const TYPE_MAP = {
60
60
  backend: ["api-design.txt"],
61
- fullstack: ["api-design.txt"],
61
+ fullstack: ["api-design.txt", "frontend-aesthetics.txt"],
62
+ frontend: ["frontend-aesthetics.txt"],
62
63
  }
63
64
 
64
65
  // Feature → knowledge file
@@ -4,7 +4,16 @@ Tailwind CSS conventions:
4
4
  - Dark mode: dark: prefix with class or media strategy
5
5
  - Component patterns: extract repeated patterns with @apply in CSS or component abstraction
6
6
  - Spacing scale: p-4 = 1rem, m-2 = 0.5rem (4px base)
7
- - Colors: bg-blue-500, text-gray-900, use project's color palette
7
+ - Colors: bg-blue-500, text-gray-900, use project's color palette from tailwind.config
8
8
  - Layout: flex, grid, container mx-auto, gap utilities
9
- - Customization: tailwind.config.js for theme extension
10
- - Avoid: inline styles, arbitrary values when a utility exists
9
+ - Customization: tailwind.config.js for theme extension (colors, fonts, spacing)
10
+ - Avoid: inline styles, arbitrary values when a utility exists
11
+
12
+ Design quality with Tailwind:
13
+ - READ tailwind.config.js first — use the project's defined colors/fonts/spacing
14
+ - Prefer semantic color names (primary, accent, muted) over raw colors (blue-500)
15
+ - Use ring utilities for focus states (ring-2 ring-offset-2)
16
+ - Transition utilities: transition-all duration-200 ease-in-out for interactions
17
+ - Shadow scale: shadow-sm → shadow → shadow-md → shadow-lg for elevation
18
+ - Use group and group-hover for parent-child hover effects
19
+ - Animate: animate-pulse for loading, animate-spin for spinners