@kkelly-offical/kkcode 0.1.6 → 0.2.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.
Files changed (163) hide show
  1. package/LICENSE +674 -674
  2. package/README.md +452 -387
  3. package/package.json +50 -46
  4. package/src/agent/agent.mjs +19 -2
  5. package/src/agent/custom-agent-loader.mjs +6 -3
  6. package/src/agent/generator.mjs +2 -2
  7. package/src/agent/prompt/assistant.txt +12 -0
  8. package/src/agent/prompt/bug-hunter.txt +90 -0
  9. package/src/agent/prompt/frontend-designer.txt +58 -58
  10. package/src/agent/prompt/guide.txt +1 -1
  11. package/src/agent/prompt/longagent-blueprint-agent.txt +83 -83
  12. package/src/agent/prompt/longagent-coding-agent.txt +37 -37
  13. package/src/agent/prompt/longagent-debugging-agent.txt +46 -46
  14. package/src/agent/prompt/longagent-preview-agent.txt +63 -63
  15. package/src/command/custom-commands.mjs +2 -2
  16. package/src/commands/agent.mjs +1 -1
  17. package/src/commands/background.mjs +145 -4
  18. package/src/commands/chat.mjs +117 -76
  19. package/src/commands/config.mjs +148 -1
  20. package/src/commands/doctor.mjs +30 -6
  21. package/src/commands/init.mjs +32 -6
  22. package/src/commands/longagent.mjs +117 -0
  23. package/src/commands/mcp.mjs +275 -43
  24. package/src/commands/permission.mjs +1 -1
  25. package/src/commands/session.mjs +195 -140
  26. package/src/commands/skill.mjs +63 -0
  27. package/src/commands/theme.mjs +1 -1
  28. package/src/config/defaults.mjs +280 -260
  29. package/src/config/import-config.mjs +1 -1
  30. package/src/config/load-config.mjs +61 -4
  31. package/src/config/schema.mjs +591 -574
  32. package/src/context.mjs +4 -1
  33. package/src/core/constants.mjs +97 -91
  34. package/src/core/types.mjs +1 -1
  35. package/src/github/api.mjs +78 -78
  36. package/src/github/auth.mjs +294 -286
  37. package/src/github/flow.mjs +298 -298
  38. package/src/github/workspace.mjs +225 -212
  39. package/src/index.mjs +84 -82
  40. package/src/knowledge/frontend-aesthetics.txt +38 -38
  41. package/src/mcp/client-http.mjs +139 -141
  42. package/src/mcp/client-sse.mjs +297 -288
  43. package/src/mcp/client-stdio.mjs +534 -533
  44. package/src/mcp/constants.mjs +2 -2
  45. package/src/mcp/registry.mjs +498 -479
  46. package/src/mcp/stdio-framing.mjs +135 -133
  47. package/src/mcp/tool-result.mjs +24 -24
  48. package/src/observability/edit-diagnostics.mjs +449 -0
  49. package/src/observability/index.mjs +42 -42
  50. package/src/observability/metrics.mjs +165 -137
  51. package/src/observability/tracer.mjs +137 -137
  52. package/src/onboarding.mjs +209 -0
  53. package/src/orchestration/background-manager.mjs +567 -372
  54. package/src/orchestration/background-worker.mjs +419 -305
  55. package/src/orchestration/interruption-reason.mjs +21 -0
  56. package/src/orchestration/longagent-manager.mjs +197 -171
  57. package/src/orchestration/stage-scheduler.mjs +733 -728
  58. package/src/orchestration/subagent-router.mjs +7 -1
  59. package/src/orchestration/task-scheduler.mjs +219 -7
  60. package/src/permission/engine.mjs +1 -1
  61. package/src/permission/exec-policy.mjs +370 -370
  62. package/src/permission/file-edit-policy.mjs +108 -0
  63. package/src/permission/prompt.mjs +1 -1
  64. package/src/permission/rules.mjs +116 -7
  65. package/src/plugin/builtin-hooks/post-edit-format.mjs +2 -1
  66. package/src/plugin/builtin-hooks/post-edit-typecheck.mjs +104 -40
  67. package/src/plugin/hook-bus.mjs +19 -5
  68. package/src/plugin/manifest-loader.mjs +222 -0
  69. package/src/provider/anthropic.mjs +396 -390
  70. package/src/provider/ollama.mjs +7 -1
  71. package/src/provider/openai.mjs +382 -340
  72. package/src/provider/retry-policy.mjs +74 -68
  73. package/src/provider/router.mjs +242 -241
  74. package/src/provider/sse.mjs +104 -104
  75. package/src/provider/wizard.mjs +556 -0
  76. package/src/repl/capability-facade.mjs +30 -0
  77. package/src/repl/command-surface.mjs +23 -0
  78. package/src/repl/controller-entry.mjs +40 -0
  79. package/src/repl/core-shell.mjs +208 -0
  80. package/src/repl/dialog-router.mjs +87 -0
  81. package/src/repl/input-engine.mjs +76 -0
  82. package/src/repl/keymap.mjs +7 -0
  83. package/src/repl/operator-surface.mjs +15 -0
  84. package/src/repl/permission-flow.mjs +49 -0
  85. package/src/repl/runtime-facade.mjs +36 -0
  86. package/src/repl/slash-router.mjs +62 -0
  87. package/src/repl/state-store.mjs +29 -0
  88. package/src/repl/turn-controller.mjs +58 -0
  89. package/src/repl/verification.mjs +23 -0
  90. package/src/repl.mjs +3368 -2929
  91. package/src/rules/load-rules.mjs +3 -3
  92. package/src/runtime.mjs +1 -1
  93. package/src/session/agent-transaction.mjs +86 -0
  94. package/src/session/checkpoint.mjs +302 -302
  95. package/src/session/compaction.mjs +36 -14
  96. package/src/session/engine.mjs +417 -227
  97. package/src/session/longagent-4stage.mjs +467 -460
  98. package/src/session/longagent-hybrid.mjs +1344 -1081
  99. package/src/session/longagent-plan.mjs +376 -365
  100. package/src/session/longagent-project-memory.mjs +53 -53
  101. package/src/session/longagent-scaffold.mjs +291 -291
  102. package/src/session/longagent-task-bus.mjs +138 -54
  103. package/src/session/longagent-utils.mjs +828 -472
  104. package/src/session/longagent.mjs +911 -884
  105. package/src/session/loop.mjs +1005 -905
  106. package/src/session/prompt/agent.txt +25 -0
  107. package/src/session/prompt/anthropic.txt +150 -150
  108. package/src/session/prompt/beast.txt +1 -1
  109. package/src/session/prompt/plan.txt +28 -6
  110. package/src/session/prompt/qwen.txt +46 -46
  111. package/src/session/recovery.mjs +21 -0
  112. package/src/session/rollback.mjs +197 -0
  113. package/src/session/routing-observability.mjs +72 -0
  114. package/src/session/runtime-state.mjs +47 -0
  115. package/src/session/store.mjs +523 -510
  116. package/src/session/system-prompt.mjs +56 -8
  117. package/src/session/task-validator.mjs +267 -267
  118. package/src/session/usability-gates.mjs +2 -2
  119. package/src/skill/builtin/commit.mjs +64 -64
  120. package/src/skill/builtin/design.mjs +76 -76
  121. package/src/skill/generator.mjs +18 -2
  122. package/src/skill/registry.mjs +642 -390
  123. package/src/storage/audit-store.mjs +18 -11
  124. package/src/storage/event-log.mjs +7 -1
  125. package/src/storage/ghost-commit-store.mjs +243 -245
  126. package/src/storage/paths.mjs +13 -0
  127. package/src/theme/default-theme.mjs +1 -1
  128. package/src/theme/markdown.mjs +4 -0
  129. package/src/theme/schema.mjs +1 -1
  130. package/src/theme/status-bar.mjs +162 -158
  131. package/src/tool/audit-wrapper.mjs +18 -2
  132. package/src/tool/edit-transaction.mjs +23 -0
  133. package/src/tool/executor.mjs +26 -1
  134. package/src/tool/file-read-state.mjs +65 -0
  135. package/src/tool/git-auto.mjs +526 -526
  136. package/src/tool/git-full-auto.mjs +487 -478
  137. package/src/tool/mutation-guard.mjs +54 -0
  138. package/src/tool/prompt/edit.txt +3 -3
  139. package/src/tool/prompt/multiedit.txt +1 -0
  140. package/src/tool/prompt/notebookedit.txt +2 -1
  141. package/src/tool/prompt/patch.txt +25 -24
  142. package/src/tool/prompt/read.txt +3 -3
  143. package/src/tool/prompt/sysinfo.txt +29 -0
  144. package/src/tool/prompt/task.txt +66 -4
  145. package/src/tool/prompt/write.txt +2 -2
  146. package/src/tool/question-prompt.mjs +17 -4
  147. package/src/tool/registry.mjs +1701 -1343
  148. package/src/tool/task-tool.mjs +14 -6
  149. package/src/ui/activity-renderer.mjs +667 -664
  150. package/src/ui/repl-background-panel.mjs +7 -0
  151. package/src/ui/repl-capability-panel.mjs +9 -0
  152. package/src/ui/repl-dashboard.mjs +54 -4
  153. package/src/ui/repl-help.mjs +110 -0
  154. package/src/ui/repl-operator-panel.mjs +12 -0
  155. package/src/ui/repl-route-feedback.mjs +35 -0
  156. package/src/ui/repl-status-view.mjs +76 -0
  157. package/src/ui/repl-task-panel.mjs +5 -0
  158. package/src/ui/repl-transcript-panel.mjs +56 -0
  159. package/src/ui/repl-turn-summary.mjs +135 -0
  160. package/src/usage/pricing.mjs +122 -121
  161. package/src/usage/usage-meter.mjs +1 -0
  162. package/src/util/git.mjs +562 -519
  163. package/src/util/template.mjs +6 -1
@@ -1,64 +1,64 @@
1
- export const name = "commit"
2
- export const description = "Stage changes and create a git commit with a descriptive message using AI-powered git automation"
3
-
4
- export async function run(args, context = {}) {
5
- const hasGitAuto = context.config?.git_auto?.enabled !== false
6
-
7
- return `Review the current git status and create a well-structured commit.
8
-
9
- ${hasGitAuto ? `🚀 Git Auto Mode Enabled
10
- The AI can now use ghost commits (temporary snapshots) to safely manage changes before you finalize them.
11
- ` : `⚙️ Standard Mode
12
- Consider enabling git_auto in your config for enhanced safety features.
13
- `}
14
-
15
- Steps:
16
- 1. Run \`git_info\` to understand the repository context.
17
- 2. Run \`git_status\` to see all changed, staged, and untracked files.
18
- 3. Review the changes to understand what needs to be committed.
19
-
20
- ${hasGitAuto ? `4. **IMPORTANT**: Before making any edits, create a ghost commit snapshot:
21
- \`git_snapshot\` - Creates a temporary snapshot you can restore later
22
-
23
- 5. After reviewing, if you need to make changes, the AI will:
24
- - First create an automatic snapshot (if git_auto.auto_snapshot is enabled)
25
- - Apply changes using \`edit\`, \`write\`, or \`git_apply_patch\`
26
-
27
- 6. If you're not satisfied with the changes:
28
- - Use \`git_list_snapshots\` to see available snapshots
29
- - Use \`git_restore\` with the snapshot_id to revert
30
-
31
- 7. When satisfied with the changes, guide the user to manually run:
32
- \`bash: git add <files> && git commit -m "<message>"\`
33
- Note: AI is forbidden from running git commit directly for security.`
34
-
35
- : `4. Stage the relevant files with manual git commands (AI cannot run git commit):
36
- - AI can suggest: \`bash: git add <files>\`
37
- - But user must manually run: \`git commit -m "<message>"\`
38
-
39
- 5. Note: AI is forbidden from executing git commit/push for security reasons.`}
40
-
41
- Commit Message Format (Conventional Commits):
42
- - feat: new feature or capability
43
- - fix: bug fix
44
- - refactor: code restructuring without behavior change
45
- - docs: documentation changes
46
- - style: formatting, whitespace, semicolons
47
- - test: adding or updating tests
48
- - chore: build process, dependencies, tooling
49
-
50
- Format: <type>(<optional scope>): <short description>
51
- Example: feat(auth): add JWT token refresh logic
52
-
53
- Important:
54
- - Keep the commit focused on a single logical change.
55
- - If there are unrelated changes, create separate commits.
56
- - The commit message subject should be under 72 characters.
57
- - Use imperative mood: "add feature" not "added feature".
58
-
59
- ${hasGitAuto ? `Safety Features:
60
- - Ghost commits are stored for 7 days then auto-cleaned
61
- - Maximum 50 snapshots per repository
62
- - Snapshots don't interfere with your normal git workflow
63
- - Use \`git_cleanup\` to manually clean up expired snapshots` : ""}`
64
- }
1
+ export const name = "commit"
2
+ export const description = "Stage changes and create a git commit with a descriptive message using AI-powered git automation"
3
+
4
+ export async function run(args, context = {}) {
5
+ const hasGitAuto = context.config?.git_auto?.enabled !== false
6
+
7
+ return `Review the current git status and create a well-structured commit.
8
+
9
+ ${hasGitAuto ? `🚀 Git Auto Mode Enabled
10
+ The AI can now use ghost commits (temporary snapshots) to safely manage changes before you finalize them.
11
+ ` : `⚙️ Standard Mode
12
+ Consider enabling git_auto in your config for enhanced safety features.
13
+ `}
14
+
15
+ Steps:
16
+ 1. Run \`git_info\` to understand the repository context.
17
+ 2. Run \`git_status\` to see all changed, staged, and untracked files.
18
+ 3. Review the changes to understand what needs to be committed.
19
+
20
+ ${hasGitAuto ? `4. **IMPORTANT**: Before making any edits, create a ghost commit snapshot:
21
+ \`git_snapshot\` - Creates a temporary snapshot you can restore later
22
+
23
+ 5. After reviewing, if you need to make changes, the AI will:
24
+ - First create an automatic snapshot (if git_auto.auto_snapshot is enabled)
25
+ - Apply changes using \`edit\`, \`write\`, or \`git_apply_patch\`
26
+
27
+ 6. If you're not satisfied with the changes:
28
+ - Use \`git_list_snapshots\` to see available snapshots
29
+ - Use \`git_restore\` with the snapshot_id to revert
30
+
31
+ 7. When satisfied with the changes, guide the user to manually run:
32
+ \`bash: git add <files> && git commit -m "<message>"\`
33
+ Note: AI is forbidden from running git commit directly for security.`
34
+
35
+ : `4. Stage the relevant files with manual git commands (AI cannot run git commit):
36
+ - AI can suggest: \`bash: git add <files>\`
37
+ - But user must manually run: \`git commit -m "<message>"\`
38
+
39
+ 5. Note: AI is forbidden from executing git commit/push for security reasons.`}
40
+
41
+ Commit Message Format (Conventional Commits):
42
+ - feat: new feature or capability
43
+ - fix: bug fix
44
+ - refactor: code restructuring without behavior change
45
+ - docs: documentation changes
46
+ - style: formatting, whitespace, semicolons
47
+ - test: adding or updating tests
48
+ - chore: build process, dependencies, tooling
49
+
50
+ Format: <type>(<optional scope>): <short description>
51
+ Example: feat(auth): add JWT token refresh logic
52
+
53
+ Important:
54
+ - Keep the commit focused on a single logical change.
55
+ - If there are unrelated changes, create separate commits.
56
+ - The commit message subject should be under 72 characters.
57
+ - Use imperative mood: "add feature" not "added feature".
58
+
59
+ ${hasGitAuto ? `Safety Features:
60
+ - Ghost commits are stored for 7 days then auto-cleaned
61
+ - Maximum 50 snapshots per repository
62
+ - Snapshots don't interfere with your normal git workflow
63
+ - Use \`git_cleanup\` to manually clean up expired snapshots` : ""}`
64
+ }
@@ -1,76 +1,76 @@
1
- import { readFile } from "node:fs/promises"
2
- import path from "node:path"
3
-
4
- export const name = "design"
5
- export const description = "Frontend design mode — generates polished, distinctive UI with strong aesthetics (usage: /design <task>)"
6
-
7
- async function detectDesignContext(cwd) {
8
- try {
9
- const pkg = JSON.parse(await readFile(path.join(cwd, "package.json"), "utf8"))
10
- const deps = { ...pkg.dependencies, ...pkg.devDependencies }
11
- const ctx = {}
12
- // Framework
13
- if (deps.next) ctx.framework = "next"
14
- else if (deps.nuxt) ctx.framework = "nuxt"
15
- else if (deps.vue) ctx.framework = "vue"
16
- else if (deps.react) ctx.framework = "react"
17
- else if (deps.svelte || deps["@sveltejs/kit"]) ctx.framework = "svelte"
18
- // CSS
19
- if (deps.tailwindcss) ctx.css = "tailwind"
20
- else if (deps.unocss) ctx.css = "unocss"
21
- else if (deps["styled-components"]) ctx.css = "styled-components"
22
- // Component lib
23
- if (deps.antd) ctx.lib = "antd"
24
- else if (deps["element-plus"]) ctx.lib = "element-plus"
25
- else if (deps["@mui/material"]) ctx.lib = "mui"
26
- else if (deps["@chakra-ui/react"]) ctx.lib = "chakra-ui"
27
- else if (deps["@mantine/core"]) ctx.lib = "mantine"
28
- else if (deps["naive-ui"]) ctx.lib = "naive-ui"
29
- return ctx
30
- } catch { return {} }
31
- }
32
-
33
- const AESTHETICS_PROMPT = `<frontend_aesthetics>
34
- You are in DESIGN MODE. Create polished, distinctive frontends — NOT generic AI output.
35
-
36
- Typography: Avoid Inter/Roboto/Arial. Use distinctive fonts (Space Grotesk, Playfair Display, Satoshi, IBM Plex). Extreme weight contrast (200 vs 800), 3x+ size jumps.
37
-
38
- Color: CSS variables for ALL colors. Dominant color + sharp accent. Draw from IDE themes (Nord, Catppuccin), cultural aesthetics. AVOID purple-gradient-on-white.
39
-
40
- Motion: One high-impact staggered reveal per page. Micro-interactions on hover/focus/press. CSS transitions + animation-delay.
41
-
42
- Layout: CSS Grid for pages, Flexbox for components. Generous whitespace. Consistent 4px spacing scale. Mobile-first.
43
-
44
- Depth: Layered gradients, backdrop-filter glass, box-shadow elevation hierarchy.
45
-
46
- NEVER: cookie-cutter card grids, generic hero sections, border-radius:9999px everywhere, gray wireframe text, no visual rhythm.
47
- </frontend_aesthetics>`
48
-
49
- export async function run(ctx) {
50
- const task = (ctx.args || "").trim()
51
- const cwd = ctx.cwd || process.cwd()
52
- const design = await detectDesignContext(cwd)
53
-
54
- const parts = [AESTHETICS_PROMPT, ""]
55
-
56
- if (Object.keys(design).length) {
57
- parts.push("## Project Design Context")
58
- if (design.framework) parts.push(`- Framework: ${design.framework}`)
59
- if (design.css) parts.push(`- CSS: ${design.css}`)
60
- if (design.lib) parts.push(`- Component Library: ${design.lib}`)
61
- parts.push("")
62
- parts.push("Read the project's existing styles/theme before writing new code. Extend, don't replace.")
63
- parts.push("")
64
- }
65
-
66
- if (task) {
67
- parts.push(`## Task`)
68
- parts.push(task)
69
- parts.push("")
70
- parts.push("Implement this with production-grade design quality. Make it look like a professional designer built it.")
71
- } else {
72
- parts.push("No task specified. Usage: /design <description of what to build>")
73
- }
74
-
75
- return parts.join("\n")
76
- }
1
+ import { readFile } from "node:fs/promises"
2
+ import path from "node:path"
3
+
4
+ export const name = "design"
5
+ export const description = "Frontend design mode — generates polished, distinctive UI with strong aesthetics (usage: /design <task>)"
6
+
7
+ async function detectDesignContext(cwd) {
8
+ try {
9
+ const pkg = JSON.parse(await readFile(path.join(cwd, "package.json"), "utf8"))
10
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies }
11
+ const ctx = {}
12
+ // Framework
13
+ if (deps.next) ctx.framework = "next"
14
+ else if (deps.nuxt) ctx.framework = "nuxt"
15
+ else if (deps.vue) ctx.framework = "vue"
16
+ else if (deps.react) ctx.framework = "react"
17
+ else if (deps.svelte || deps["@sveltejs/kit"]) ctx.framework = "svelte"
18
+ // CSS
19
+ if (deps.tailwindcss) ctx.css = "tailwind"
20
+ else if (deps.unocss) ctx.css = "unocss"
21
+ else if (deps["styled-components"]) ctx.css = "styled-components"
22
+ // Component lib
23
+ if (deps.antd) ctx.lib = "antd"
24
+ else if (deps["element-plus"]) ctx.lib = "element-plus"
25
+ else if (deps["@mui/material"]) ctx.lib = "mui"
26
+ else if (deps["@chakra-ui/react"]) ctx.lib = "chakra-ui"
27
+ else if (deps["@mantine/core"]) ctx.lib = "mantine"
28
+ else if (deps["naive-ui"]) ctx.lib = "naive-ui"
29
+ return ctx
30
+ } catch { return {} }
31
+ }
32
+
33
+ const AESTHETICS_PROMPT = `<frontend_aesthetics>
34
+ You are in DESIGN MODE. Create polished, distinctive frontends — NOT generic AI output.
35
+
36
+ Typography: Avoid Inter/Roboto/Arial. Use distinctive fonts (Space Grotesk, Playfair Display, Satoshi, IBM Plex). Extreme weight contrast (200 vs 800), 3x+ size jumps.
37
+
38
+ Color: CSS variables for ALL colors. Dominant color + sharp accent. Draw from IDE themes (Nord, Catppuccin), cultural aesthetics. AVOID purple-gradient-on-white.
39
+
40
+ Motion: One high-impact staggered reveal per page. Micro-interactions on hover/focus/press. CSS transitions + animation-delay.
41
+
42
+ Layout: CSS Grid for pages, Flexbox for components. Generous whitespace. Consistent 4px spacing scale. Mobile-first.
43
+
44
+ Depth: Layered gradients, backdrop-filter glass, box-shadow elevation hierarchy.
45
+
46
+ NEVER: cookie-cutter card grids, generic hero sections, border-radius:9999px everywhere, gray wireframe text, no visual rhythm.
47
+ </frontend_aesthetics>`
48
+
49
+ export async function run(ctx) {
50
+ const task = (ctx.args || "").trim()
51
+ const cwd = ctx.cwd || process.cwd()
52
+ const design = await detectDesignContext(cwd)
53
+
54
+ const parts = [AESTHETICS_PROMPT, ""]
55
+
56
+ if (Object.keys(design).length) {
57
+ parts.push("## Project Design Context")
58
+ if (design.framework) parts.push(`- Framework: ${design.framework}`)
59
+ if (design.css) parts.push(`- CSS: ${design.css}`)
60
+ if (design.lib) parts.push(`- Component Library: ${design.lib}`)
61
+ parts.push("")
62
+ parts.push("Read the project's existing styles/theme before writing new code. Extend, don't replace.")
63
+ parts.push("")
64
+ }
65
+
66
+ if (task) {
67
+ parts.push(`## Task`)
68
+ parts.push(task)
69
+ parts.push("")
70
+ parts.push("Implement this with production-grade design quality. Make it look like a professional designer built it.")
71
+ } else {
72
+ parts.push("No task specified. Usage: /design <description of what to build>")
73
+ }
74
+
75
+ return parts.join("\n")
76
+ }
@@ -1,7 +1,7 @@
1
1
  import { writeFile, mkdir } from "node:fs/promises"
2
2
  import { join, basename } from "node:path"
3
- import { homedir } from "node:os"
4
3
  import { requestProvider } from "../provider/router.mjs"
4
+ import { userRootDir } from "../storage/paths.mjs"
5
5
 
6
6
  const SKILL_GEN_SYSTEM = `You are a skill generator for kkcode, a terminal AI coding agent.
7
7
  Your task is to generate a skill file based on the user's description.
@@ -86,6 +86,22 @@ export async function generateSkill({ description, configState, providerType, mo
86
86
  const fenceMatch = content.match(/```(?:markdown|javascript|js|mjs)?\n([\s\S]*?)\n```/)
87
87
  if (fenceMatch) content = fenceMatch[1]
88
88
 
89
+ // Safety: reject .mjs skills that contain dangerous patterns
90
+ if (type === "mjs") {
91
+ const dangerPatterns = [
92
+ /child_process/,
93
+ /\bexec\s*\(/,
94
+ /\bspawn\s*\(/,
95
+ /\beval\s*\(/,
96
+ /Function\s*\(/,
97
+ /require\s*\(\s*['"]fs['"]\s*\)/
98
+ ]
99
+ const hasDanger = dangerPatterns.some(p => p.test(content))
100
+ if (hasDanger) {
101
+ return { name, filename: `${name}.${type}`, content, type, needsReview: true, reviewReason: "contains potentially dangerous code patterns (child_process, exec, eval, etc.)" }
102
+ }
103
+ }
104
+
89
105
  const filename = `${name}.${type}`
90
106
  return { name, filename, content, type }
91
107
  }
@@ -94,7 +110,7 @@ export async function generateSkill({ description, configState, providerType, mo
94
110
  * Save a skill to the global skills directory.
95
111
  */
96
112
  export async function saveSkillGlobal(filename, content) {
97
- const dir = join(homedir(), ".kkcode", "skills")
113
+ const dir = join(userRootDir(), "skills")
98
114
  await mkdir(dir, { recursive: true })
99
115
  const filePath = join(dir, filename)
100
116
  await writeFile(filePath, content, "utf-8")