@kkelly-offical/kkcode 0.1.7 → 0.2.3-preview.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 (166) hide show
  1. package/LICENSE +674 -674
  2. package/README.md +474 -387
  3. package/package.json +50 -46
  4. package/src/agent/agent.mjs +228 -220
  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 +89 -89
  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/commands/update.mjs +32 -0
  29. package/src/config/defaults.mjs +289 -260
  30. package/src/config/import-config.mjs +1 -1
  31. package/src/config/load-config.mjs +61 -4
  32. package/src/config/schema.mjs +604 -574
  33. package/src/context.mjs +4 -1
  34. package/src/core/constants.mjs +97 -91
  35. package/src/core/types.mjs +1 -1
  36. package/src/github/api.mjs +78 -78
  37. package/src/github/auth.mjs +294 -286
  38. package/src/github/flow.mjs +298 -298
  39. package/src/github/workspace.mjs +225 -212
  40. package/src/index.mjs +87 -82
  41. package/src/knowledge/frontend-aesthetics.txt +38 -38
  42. package/src/mcp/client-http.mjs +139 -141
  43. package/src/mcp/client-sse.mjs +297 -288
  44. package/src/mcp/client-stdio.mjs +534 -533
  45. package/src/mcp/constants.mjs +4 -2
  46. package/src/mcp/registry.mjs +498 -479
  47. package/src/mcp/stdio-framing.mjs +135 -133
  48. package/src/mcp/tool-result.mjs +24 -24
  49. package/src/observability/edit-diagnostics.mjs +449 -0
  50. package/src/observability/index.mjs +42 -42
  51. package/src/observability/metrics.mjs +165 -137
  52. package/src/observability/tracer.mjs +137 -137
  53. package/src/onboarding.mjs +209 -0
  54. package/src/orchestration/background-manager.mjs +567 -372
  55. package/src/orchestration/background-worker.mjs +419 -305
  56. package/src/orchestration/interruption-reason.mjs +21 -0
  57. package/src/orchestration/longagent-manager.mjs +197 -171
  58. package/src/orchestration/stage-scheduler.mjs +733 -728
  59. package/src/orchestration/subagent-router.mjs +7 -1
  60. package/src/orchestration/task-scheduler.mjs +219 -7
  61. package/src/permission/engine.mjs +1 -1
  62. package/src/permission/exec-policy.mjs +370 -370
  63. package/src/permission/file-edit-policy.mjs +108 -0
  64. package/src/permission/prompt.mjs +1 -1
  65. package/src/permission/rules.mjs +116 -7
  66. package/src/plugin/builtin-hooks/post-edit-format.mjs +2 -1
  67. package/src/plugin/builtin-hooks/post-edit-typecheck.mjs +104 -40
  68. package/src/plugin/hook-bus.mjs +19 -5
  69. package/src/plugin/manifest-loader.mjs +222 -0
  70. package/src/provider/anthropic.mjs +396 -390
  71. package/src/provider/ollama.mjs +7 -1
  72. package/src/provider/openai.mjs +382 -340
  73. package/src/provider/retry-policy.mjs +74 -68
  74. package/src/provider/router.mjs +242 -241
  75. package/src/provider/sse.mjs +104 -104
  76. package/src/provider/wizard.mjs +556 -0
  77. package/src/repl/capability-facade.mjs +30 -0
  78. package/src/repl/command-surface.mjs +23 -0
  79. package/src/repl/controller-entry.mjs +40 -0
  80. package/src/repl/core-shell.mjs +208 -0
  81. package/src/repl/dialog-router.mjs +87 -0
  82. package/src/repl/input-engine.mjs +76 -0
  83. package/src/repl/keymap.mjs +7 -0
  84. package/src/repl/operator-surface.mjs +15 -0
  85. package/src/repl/permission-flow.mjs +49 -0
  86. package/src/repl/runtime-facade.mjs +36 -0
  87. package/src/repl/slash-router.mjs +62 -0
  88. package/src/repl/state-store.mjs +29 -0
  89. package/src/repl/turn-controller.mjs +58 -0
  90. package/src/repl/verification.mjs +23 -0
  91. package/src/repl.mjs +3371 -2981
  92. package/src/rules/load-rules.mjs +3 -3
  93. package/src/runtime.mjs +1 -1
  94. package/src/session/agent-transaction.mjs +86 -0
  95. package/src/session/checkpoint.mjs +302 -302
  96. package/src/session/compaction.mjs +298 -298
  97. package/src/session/engine.mjs +417 -232
  98. package/src/session/longagent-4stage.mjs +467 -460
  99. package/src/session/longagent-hybrid.mjs +1344 -1097
  100. package/src/session/longagent-plan.mjs +376 -365
  101. package/src/session/longagent-project-memory.mjs +53 -53
  102. package/src/session/longagent-scaffold.mjs +291 -291
  103. package/src/session/longagent-task-bus.mjs +138 -54
  104. package/src/session/longagent-utils.mjs +828 -472
  105. package/src/session/longagent.mjs +911 -900
  106. package/src/session/loop.mjs +1005 -930
  107. package/src/session/prompt/agent.txt +25 -25
  108. package/src/session/prompt/anthropic.txt +150 -150
  109. package/src/session/prompt/beast.txt +1 -1
  110. package/src/session/prompt/plan.txt +31 -31
  111. package/src/session/prompt/qwen.txt +46 -46
  112. package/src/session/recovery.mjs +21 -0
  113. package/src/session/rollback.mjs +196 -195
  114. package/src/session/routing-observability.mjs +72 -0
  115. package/src/session/runtime-state.mjs +47 -0
  116. package/src/session/store.mjs +523 -519
  117. package/src/session/system-prompt.mjs +308 -273
  118. package/src/session/task-validator.mjs +267 -267
  119. package/src/session/usability-gates.mjs +2 -2
  120. package/src/skill/builtin/commit.mjs +64 -64
  121. package/src/skill/builtin/design.mjs +76 -76
  122. package/src/skill/generator.mjs +18 -2
  123. package/src/skill/registry.mjs +642 -390
  124. package/src/storage/audit-store.mjs +18 -11
  125. package/src/storage/event-log.mjs +7 -1
  126. package/src/storage/ghost-commit-store.mjs +243 -245
  127. package/src/storage/paths.mjs +17 -0
  128. package/src/theme/default-theme.mjs +1 -1
  129. package/src/theme/markdown.mjs +4 -0
  130. package/src/theme/schema.mjs +1 -1
  131. package/src/theme/status-bar.mjs +162 -158
  132. package/src/tool/audit-wrapper.mjs +18 -2
  133. package/src/tool/edit-transaction.mjs +23 -0
  134. package/src/tool/executor.mjs +26 -1
  135. package/src/tool/file-read-state.mjs +65 -0
  136. package/src/tool/git-auto.mjs +526 -526
  137. package/src/tool/git-full-auto.mjs +487 -478
  138. package/src/tool/mutation-guard.mjs +54 -0
  139. package/src/tool/prompt/edit.txt +3 -3
  140. package/src/tool/prompt/multiedit.txt +1 -0
  141. package/src/tool/prompt/notebookedit.txt +2 -1
  142. package/src/tool/prompt/patch.txt +25 -24
  143. package/src/tool/prompt/read.txt +3 -3
  144. package/src/tool/prompt/sysinfo.txt +29 -0
  145. package/src/tool/prompt/task.txt +66 -4
  146. package/src/tool/prompt/write.txt +2 -2
  147. package/src/tool/question-prompt.mjs +99 -93
  148. package/src/tool/registry.mjs +1701 -1343
  149. package/src/tool/task-tool.mjs +14 -6
  150. package/src/ui/activity-renderer.mjs +667 -664
  151. package/src/ui/repl-background-panel.mjs +7 -0
  152. package/src/ui/repl-capability-panel.mjs +9 -0
  153. package/src/ui/repl-dashboard.mjs +54 -4
  154. package/src/ui/repl-help.mjs +110 -0
  155. package/src/ui/repl-operator-panel.mjs +12 -0
  156. package/src/ui/repl-route-feedback.mjs +35 -0
  157. package/src/ui/repl-status-view.mjs +76 -0
  158. package/src/ui/repl-task-panel.mjs +5 -0
  159. package/src/ui/repl-transcript-panel.mjs +56 -0
  160. package/src/ui/repl-turn-summary.mjs +135 -0
  161. package/src/update/checker.mjs +184 -0
  162. package/src/usage/pricing.mjs +122 -121
  163. package/src/usage/usage-meter.mjs +1 -0
  164. package/src/util/git.mjs +562 -519
  165. package/src/util/template.mjs +6 -1
  166. package/src/version.mjs +3 -0
@@ -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")