@kkelly-offical/kkcode 0.1.2

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 (196) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +445 -0
  3. package/package.json +46 -0
  4. package/src/agent/agent.mjs +170 -0
  5. package/src/agent/custom-agent-loader.mjs +158 -0
  6. package/src/agent/generator.mjs +115 -0
  7. package/src/agent/prompt/architect.txt +36 -0
  8. package/src/agent/prompt/build-fixer.txt +71 -0
  9. package/src/agent/prompt/build.txt +101 -0
  10. package/src/agent/prompt/compaction.txt +12 -0
  11. package/src/agent/prompt/explore.txt +29 -0
  12. package/src/agent/prompt/guide.txt +40 -0
  13. package/src/agent/prompt/longagent.txt +178 -0
  14. package/src/agent/prompt/plan.txt +50 -0
  15. package/src/agent/prompt/researcher.txt +23 -0
  16. package/src/agent/prompt/reviewer.txt +44 -0
  17. package/src/agent/prompt/security-reviewer.txt +62 -0
  18. package/src/agent/prompt/tdd-guide.txt +84 -0
  19. package/src/agent/prompt/title.txt +8 -0
  20. package/src/command/custom-commands.mjs +57 -0
  21. package/src/commands/agent.mjs +71 -0
  22. package/src/commands/audit.mjs +77 -0
  23. package/src/commands/background.mjs +86 -0
  24. package/src/commands/chat.mjs +114 -0
  25. package/src/commands/command.mjs +41 -0
  26. package/src/commands/config.mjs +44 -0
  27. package/src/commands/doctor.mjs +148 -0
  28. package/src/commands/hook.mjs +29 -0
  29. package/src/commands/init.mjs +141 -0
  30. package/src/commands/longagent.mjs +100 -0
  31. package/src/commands/mcp.mjs +89 -0
  32. package/src/commands/permission.mjs +36 -0
  33. package/src/commands/prompt.mjs +42 -0
  34. package/src/commands/review.mjs +266 -0
  35. package/src/commands/rule.mjs +34 -0
  36. package/src/commands/session.mjs +235 -0
  37. package/src/commands/theme.mjs +98 -0
  38. package/src/commands/usage.mjs +91 -0
  39. package/src/config/defaults.mjs +195 -0
  40. package/src/config/import-config.mjs +76 -0
  41. package/src/config/load-config.mjs +76 -0
  42. package/src/config/schema.mjs +509 -0
  43. package/src/context.mjs +40 -0
  44. package/src/core/constants.mjs +46 -0
  45. package/src/core/errors.mjs +57 -0
  46. package/src/core/events.mjs +29 -0
  47. package/src/core/types.mjs +57 -0
  48. package/src/github/api.mjs +78 -0
  49. package/src/github/auth.mjs +286 -0
  50. package/src/github/flow.mjs +298 -0
  51. package/src/github/workspace.mjs +212 -0
  52. package/src/index.mjs +82 -0
  53. package/src/knowledge/api-design.txt +9 -0
  54. package/src/knowledge/cpp.txt +10 -0
  55. package/src/knowledge/docker.txt +10 -0
  56. package/src/knowledge/dotnet.txt +9 -0
  57. package/src/knowledge/electron.txt +10 -0
  58. package/src/knowledge/flutter.txt +10 -0
  59. package/src/knowledge/go.txt +9 -0
  60. package/src/knowledge/graphql.txt +10 -0
  61. package/src/knowledge/java.txt +9 -0
  62. package/src/knowledge/kotlin.txt +10 -0
  63. package/src/knowledge/loader.mjs +125 -0
  64. package/src/knowledge/next.txt +8 -0
  65. package/src/knowledge/node.txt +8 -0
  66. package/src/knowledge/nuxt.txt +9 -0
  67. package/src/knowledge/php.txt +10 -0
  68. package/src/knowledge/python.txt +10 -0
  69. package/src/knowledge/react-native.txt +10 -0
  70. package/src/knowledge/react.txt +9 -0
  71. package/src/knowledge/ruby.txt +11 -0
  72. package/src/knowledge/rust.txt +9 -0
  73. package/src/knowledge/svelte.txt +9 -0
  74. package/src/knowledge/swift.txt +10 -0
  75. package/src/knowledge/tailwind.txt +10 -0
  76. package/src/knowledge/testing.txt +8 -0
  77. package/src/knowledge/typescript.txt +8 -0
  78. package/src/knowledge/vue.txt +9 -0
  79. package/src/mcp/client-http.mjs +157 -0
  80. package/src/mcp/client-sse.mjs +286 -0
  81. package/src/mcp/client-stdio.mjs +451 -0
  82. package/src/mcp/registry.mjs +394 -0
  83. package/src/mcp/stdio-framing.mjs +127 -0
  84. package/src/orchestration/background-manager.mjs +358 -0
  85. package/src/orchestration/background-worker.mjs +245 -0
  86. package/src/orchestration/longagent-manager.mjs +116 -0
  87. package/src/orchestration/stage-scheduler.mjs +489 -0
  88. package/src/orchestration/subagent-router.mjs +62 -0
  89. package/src/orchestration/task-scheduler.mjs +74 -0
  90. package/src/permission/engine.mjs +92 -0
  91. package/src/permission/exec-policy.mjs +372 -0
  92. package/src/permission/prompt.mjs +39 -0
  93. package/src/permission/rules.mjs +120 -0
  94. package/src/permission/workspace-trust.mjs +44 -0
  95. package/src/plugin/builtin-hooks/console-warn.mjs +41 -0
  96. package/src/plugin/builtin-hooks/extract-patterns.mjs +75 -0
  97. package/src/plugin/builtin-hooks/post-edit-format.mjs +57 -0
  98. package/src/plugin/builtin-hooks/post-edit-typecheck.mjs +61 -0
  99. package/src/plugin/builtin-hooks/strategic-compaction.mjs +38 -0
  100. package/src/plugin/hook-bus.mjs +154 -0
  101. package/src/provider/anthropic.mjs +389 -0
  102. package/src/provider/ollama.mjs +236 -0
  103. package/src/provider/openai-compatible.mjs +1 -0
  104. package/src/provider/openai.mjs +339 -0
  105. package/src/provider/retry-policy.mjs +68 -0
  106. package/src/provider/router.mjs +228 -0
  107. package/src/provider/sse.mjs +91 -0
  108. package/src/repl.mjs +2929 -0
  109. package/src/review/diff-parser.mjs +36 -0
  110. package/src/review/rejection-queue.mjs +62 -0
  111. package/src/review/review-store.mjs +21 -0
  112. package/src/review/risk-score.mjs +61 -0
  113. package/src/rules/load-rules.mjs +64 -0
  114. package/src/runtime.mjs +1 -0
  115. package/src/session/checkpoint.mjs +239 -0
  116. package/src/session/compaction.mjs +276 -0
  117. package/src/session/engine.mjs +225 -0
  118. package/src/session/instinct-manager.mjs +172 -0
  119. package/src/session/instruction-loader.mjs +25 -0
  120. package/src/session/longagent-plan.mjs +329 -0
  121. package/src/session/longagent-scaffold.mjs +100 -0
  122. package/src/session/longagent.mjs +1462 -0
  123. package/src/session/loop.mjs +905 -0
  124. package/src/session/memory-loader.mjs +75 -0
  125. package/src/session/project-context.mjs +367 -0
  126. package/src/session/prompt/anthropic.txt +151 -0
  127. package/src/session/prompt/beast.txt +37 -0
  128. package/src/session/prompt/max-steps.txt +6 -0
  129. package/src/session/prompt/plan.txt +9 -0
  130. package/src/session/prompt/qwen.txt +46 -0
  131. package/src/session/prompt-loader.mjs +18 -0
  132. package/src/session/recovery.mjs +52 -0
  133. package/src/session/store.mjs +503 -0
  134. package/src/session/system-prompt.mjs +260 -0
  135. package/src/session/task-validator.mjs +266 -0
  136. package/src/session/usability-gates.mjs +379 -0
  137. package/src/skill/builtin/backend-patterns.mjs +123 -0
  138. package/src/skill/builtin/commit.mjs +64 -0
  139. package/src/skill/builtin/debug.mjs +45 -0
  140. package/src/skill/builtin/frontend-patterns.mjs +120 -0
  141. package/src/skill/builtin/frontend.mjs +188 -0
  142. package/src/skill/builtin/init.mjs +220 -0
  143. package/src/skill/builtin/review.mjs +49 -0
  144. package/src/skill/builtin/security-checklist.mjs +80 -0
  145. package/src/skill/builtin/tdd.mjs +54 -0
  146. package/src/skill/generator.mjs +113 -0
  147. package/src/skill/registry.mjs +336 -0
  148. package/src/storage/audit-store.mjs +83 -0
  149. package/src/storage/event-log.mjs +82 -0
  150. package/src/storage/ghost-commit-store.mjs +235 -0
  151. package/src/storage/json-store.mjs +53 -0
  152. package/src/storage/paths.mjs +148 -0
  153. package/src/theme/color.mjs +64 -0
  154. package/src/theme/default-theme.mjs +29 -0
  155. package/src/theme/load-theme.mjs +71 -0
  156. package/src/theme/markdown.mjs +135 -0
  157. package/src/theme/schema.mjs +45 -0
  158. package/src/theme/status-bar.mjs +158 -0
  159. package/src/tool/audit-wrapper.mjs +38 -0
  160. package/src/tool/edit-transaction.mjs +126 -0
  161. package/src/tool/executor.mjs +109 -0
  162. package/src/tool/file-lock-manager.mjs +85 -0
  163. package/src/tool/git-auto.mjs +545 -0
  164. package/src/tool/git-full-auto.mjs +478 -0
  165. package/src/tool/image-util.mjs +276 -0
  166. package/src/tool/prompt/background_cancel.txt +1 -0
  167. package/src/tool/prompt/background_output.txt +1 -0
  168. package/src/tool/prompt/bash.txt +71 -0
  169. package/src/tool/prompt/codesearch.txt +18 -0
  170. package/src/tool/prompt/edit.txt +27 -0
  171. package/src/tool/prompt/enter_plan.txt +74 -0
  172. package/src/tool/prompt/exit_plan.txt +62 -0
  173. package/src/tool/prompt/glob.txt +33 -0
  174. package/src/tool/prompt/grep.txt +43 -0
  175. package/src/tool/prompt/list.txt +8 -0
  176. package/src/tool/prompt/multiedit.txt +20 -0
  177. package/src/tool/prompt/notebookedit.txt +21 -0
  178. package/src/tool/prompt/patch.txt +24 -0
  179. package/src/tool/prompt/question.txt +44 -0
  180. package/src/tool/prompt/read.txt +40 -0
  181. package/src/tool/prompt/task.txt +83 -0
  182. package/src/tool/prompt/todowrite.txt +117 -0
  183. package/src/tool/prompt/webfetch.txt +38 -0
  184. package/src/tool/prompt/websearch.txt +43 -0
  185. package/src/tool/prompt/write.txt +38 -0
  186. package/src/tool/prompt-loader.mjs +18 -0
  187. package/src/tool/question-prompt.mjs +86 -0
  188. package/src/tool/registry.mjs +1309 -0
  189. package/src/tool/task-tool.mjs +28 -0
  190. package/src/ui/activity-renderer.mjs +410 -0
  191. package/src/ui/repl-dashboard.mjs +357 -0
  192. package/src/usage/pricing.mjs +121 -0
  193. package/src/usage/usage-meter.mjs +113 -0
  194. package/src/util/git.mjs +496 -0
  195. package/src/util/template.mjs +10 -0
  196. package/src/util/yaml.mjs +100 -0
@@ -0,0 +1,478 @@
1
+ import path from "node:path"
2
+ import { exec } from "node:child_process"
3
+ import { promisify } from "node:util"
4
+ import {
5
+ isGitRepo,
6
+ currentBranch,
7
+ commitAll as gitCommitAll
8
+ } from "../util/git.mjs"
9
+ import { gitSnapshotTool } from "./git-auto.mjs"
10
+ import { isFullAutoMode, getPolicyMode } from "../permission/exec-policy.mjs"
11
+
12
+ const execAsync = promisify(exec)
13
+
14
+ /**
15
+ * 全自动化 Git 操作工具
16
+ *
17
+ * 当启用 full_auto 模式时,AI 可以:
18
+ * 1. 自动 stage 更改 (git add)
19
+ * 2. 自动创建提交 (git commit)
20
+ * 3. 自动推送到远程 (git push)
21
+ * 4. 执行其他 Git 操作
22
+ *
23
+ * 警告:此模式会赋予 AI 更大的权限,可能导致不可逆的操作。
24
+ * 建议仅在受控环境或 CI/CD 场景中使用。
25
+ */
26
+
27
+ /**
28
+ * 执行 Git 命令
29
+ */
30
+ async function runGit(args, cwd, timeoutMs = 30000) {
31
+ try {
32
+ const { stdout, stderr } = await execAsync(
33
+ `git ${args.join(" ")}`,
34
+ { cwd, timeout: timeoutMs, encoding: "utf8" }
35
+ )
36
+ return {
37
+ ok: true,
38
+ stdout: stdout?.trim() || "",
39
+ stderr: stderr?.trim() || ""
40
+ }
41
+ } catch (error) {
42
+ return {
43
+ ok: false,
44
+ stdout: error.stdout?.trim() || "",
45
+ stderr: error.stderr?.trim() || "",
46
+ error: error.message
47
+ }
48
+ }
49
+ }
50
+
51
+ /**
52
+ * 生成提交信息
53
+ * 基于更改内容自动生成符合 Conventional Commits 格式的消息
54
+ */
55
+ async function generateCommitMessage(cwd, customMessage = null) {
56
+ if (customMessage) return customMessage
57
+
58
+ // 获取变更的概要
59
+ const result = await runGit(["status", "--short"], cwd)
60
+ if (!result.ok) return "chore: update files"
61
+
62
+ const files = result.stdout.split("\n").filter(Boolean)
63
+ if (files.length === 0) return "chore: empty commit"
64
+
65
+ // 分析文件类型来确定提交类型
66
+ const hasTests = files.some(f => f.includes("test") || f.includes("spec"))
67
+ const hasDocs = files.some(f => f.endsWith(".md") || f.includes("doc"))
68
+ const hasConfig = files.some(f =>
69
+ f.includes("config") ||
70
+ f.endsWith(".json") ||
71
+ f.endsWith(".yaml") ||
72
+ f.endsWith(".yml")
73
+ )
74
+
75
+ let type = "chore"
76
+ if (hasTests) type = "test"
77
+ else if (hasDocs) type = "docs"
78
+ else if (hasConfig) type = "chore"
79
+ else if (files.some(f => f.includes("fix") || f.includes("bug"))) type = "fix"
80
+ else if (files.some(f => f.includes("feat") || f.includes("feature"))) type = "feat"
81
+ else if (files.length > 5) type = "refactor"
82
+
83
+ // 生成描述
84
+ let description
85
+ if (files.length === 1) {
86
+ const file = files[0].slice(3) // 移除状态前缀
87
+ description = `update ${path.basename(file)}`
88
+ } else {
89
+ const scope = files.length <= 3
90
+ ? files.map(f => path.basename(f.slice(3))).join(", ")
91
+ : `${files.length} files`
92
+ description = `update ${scope}`
93
+ }
94
+
95
+ return `${type}: ${description}`
96
+ }
97
+
98
+ // ============================================================================
99
+ // Tool: git_auto_commit - 全自动提交
100
+ // ============================================================================
101
+
102
+ export const gitAutoCommitTool = {
103
+ name: "git_auto_commit",
104
+ description: "[FULL-AUTO MODE] Automatically stage all changes and create a git commit. Only available when git_auto.full_auto and git_auto.auto_commit are enabled. This operation cannot be undone without git restore.",
105
+ inputSchema: {
106
+ type: "object",
107
+ properties: {
108
+ message: {
109
+ type: "string",
110
+ description: "Commit message (optional, will be auto-generated if not provided)"
111
+ },
112
+ stage_all: {
113
+ type: "boolean",
114
+ description: "Stage all changes including untracked files (default: true)"
115
+ },
116
+ amend: {
117
+ type: "boolean",
118
+ description: "Amend the previous commit instead of creating a new one (default: false)"
119
+ },
120
+ no_verify: {
121
+ type: "boolean",
122
+ description: "Bypass pre-commit hooks (default: false)"
123
+ }
124
+ },
125
+ required: []
126
+ },
127
+ async execute(args, ctx) {
128
+ const cwd = ctx.cwd || process.cwd()
129
+
130
+ // 检查全自动化模式
131
+ if (!isFullAutoMode(ctx.config)) {
132
+ return {
133
+ ok: false,
134
+ error: "full_auto_disabled",
135
+ message: "Full-auto mode is not enabled. Set git_auto.full_auto: true and git_auto.auto_commit: true in your config."
136
+ }
137
+ }
138
+
139
+ if (ctx.config?.git_auto?.auto_commit !== true) {
140
+ return {
141
+ ok: false,
142
+ error: "auto_commit_disabled",
143
+ message: "Auto commit is not enabled. Set git_auto.auto_commit: true in your config."
144
+ }
145
+ }
146
+
147
+ // 检查是否是 Git 仓库
148
+ if (!(await isGitRepo(cwd))) {
149
+ return {
150
+ ok: false,
151
+ error: "not_a_git_repo",
152
+ message: "Current directory is not a git repository"
153
+ }
154
+ }
155
+
156
+ // 检查是否有更改
157
+ const statusResult = await runGit(["status", "--porcelain"], cwd)
158
+ if (!statusResult.ok) {
159
+ return {
160
+ ok: false,
161
+ error: "status_check_failed",
162
+ message: statusResult.error
163
+ }
164
+ }
165
+
166
+ if (!statusResult.stdout.trim()) {
167
+ return {
168
+ ok: true,
169
+ skipped: true,
170
+ message: "No changes to commit"
171
+ }
172
+ }
173
+
174
+ // 1. 创建快照(用于可能的回滚)
175
+ const snapshotResult = await gitSnapshotTool.execute(
176
+ { auto: true, message: "Pre-auto-commit snapshot" },
177
+ { cwd, sessionId: ctx.sessionId, config: ctx.config }
178
+ )
179
+
180
+ const snapshotId = snapshotResult.ok ? snapshotResult.snapshot?.id : null
181
+
182
+ // 2. Stage 更改
183
+ const stageAll = args.stage_all !== false // 默认 true
184
+ if (stageAll) {
185
+ const addResult = await runGit(["add", "-A"], cwd)
186
+ if (!addResult.ok) {
187
+ return {
188
+ ok: false,
189
+ error: "stage_failed",
190
+ message: `Failed to stage changes: ${addResult.stderr}`,
191
+ snapshotId
192
+ }
193
+ }
194
+ }
195
+
196
+ // 3. 生成或获取提交信息
197
+ const message = await generateCommitMessage(cwd, args.message)
198
+
199
+ // 4. 创建提交
200
+ const commitArgs = ["commit", "-m", message]
201
+ if (args.amend) commitArgs.push("--amend")
202
+ if (args.no_verify) commitArgs.push("--no-verify")
203
+
204
+ const commitResult = await runGit(commitArgs, cwd)
205
+ if (!commitResult.ok) {
206
+ return {
207
+ ok: false,
208
+ error: "commit_failed",
209
+ message: `Failed to create commit: ${commitResult.stderr}`,
210
+ snapshotId,
211
+ staged: stageAll
212
+ }
213
+ }
214
+
215
+ // 5. 获取提交信息
216
+ const logResult = await runGit(["log", "-1", "--format=%H|%s"], cwd)
217
+ const [hash, subject] = logResult.ok
218
+ ? logResult.stdout.split("|")
219
+ : ["", message]
220
+
221
+ return {
222
+ ok: true,
223
+ commit: {
224
+ hash: hash?.slice(0, 8),
225
+ fullHash: hash,
226
+ message: subject || message,
227
+ branch: await currentBranch(cwd)
228
+ },
229
+ snapshotId,
230
+ staged: stageAll,
231
+ message: `Created commit ${hash?.slice(0, 8)}: ${subject || message}`,
232
+ warning: "This is an automatic commit. Use git_restore with the snapshot_id to revert if needed."
233
+ }
234
+ }
235
+ }
236
+
237
+ // ============================================================================
238
+ // Tool: git_auto_push - 全自动推送
239
+ // ============================================================================
240
+
241
+ export const gitAutoPushTool = {
242
+ name: "git_auto_push",
243
+ description: "[FULL-AUTO MODE] Automatically push commits to remote. Only available when git_auto.full_auto and git_auto.auto_push are enabled. WARNING: This will upload your changes to remote repository.",
244
+ inputSchema: {
245
+ type: "object",
246
+ properties: {
247
+ remote: {
248
+ type: "string",
249
+ description: "Remote name (default: origin)"
250
+ },
251
+ branch: {
252
+ type: "string",
253
+ description: "Branch name (default: current branch)"
254
+ },
255
+ force: {
256
+ type: "boolean",
257
+ description: "Force push (DANGEROUS, only works if allow_dangerous_ops is also enabled) (default: false)"
258
+ },
259
+ set_upstream: {
260
+ type: "boolean",
261
+ description: "Set upstream for new branch (default: true)"
262
+ }
263
+ },
264
+ required: []
265
+ },
266
+ async execute(args, ctx) {
267
+ const cwd = ctx.cwd || process.cwd()
268
+
269
+ // 检查全自动化模式
270
+ if (!isFullAutoMode(ctx.config)) {
271
+ return {
272
+ ok: false,
273
+ error: "full_auto_disabled",
274
+ message: "Full-auto mode is not enabled. Set git_auto.full_auto: true and git_auto.auto_push: true in your config."
275
+ }
276
+ }
277
+
278
+ if (ctx.config?.git_auto?.auto_push !== true) {
279
+ return {
280
+ ok: false,
281
+ error: "auto_push_disabled",
282
+ message: "Auto push is not enabled. Set git_auto.auto_push: true in your config."
283
+ }
284
+ }
285
+
286
+ // 检查是否是 Git 仓库
287
+ if (!(await isGitRepo(cwd))) {
288
+ return {
289
+ ok: false,
290
+ error: "not_a_git_repo",
291
+ message: "Current directory is not a git repository"
292
+ }
293
+ }
294
+
295
+ const remote = args.remote || "origin"
296
+ const branch = args.branch || await currentBranch(cwd)
297
+
298
+ if (!branch) {
299
+ return {
300
+ ok: false,
301
+ error: "no_branch",
302
+ message: "Could not determine current branch"
303
+ }
304
+ }
305
+
306
+ // 检查是否需要设置 upstream
307
+ const setUpstream = args.set_upstream !== false && branch !== "main" && branch !== "master"
308
+
309
+ // 构建 push 命令
310
+ const pushArgs = ["push"]
311
+ if (args.force) {
312
+ if (ctx.config?.git_auto?.allow_dangerous_ops !== true) {
313
+ return {
314
+ ok: false,
315
+ error: "force_push_forbidden",
316
+ message: "Force push is forbidden. Enable git_auto.allow_dangerous_ops: true to allow force push."
317
+ }
318
+ }
319
+ pushArgs.push("--force")
320
+ }
321
+ if (setUpstream) pushArgs.push("-u")
322
+ pushArgs.push(remote, branch)
323
+
324
+ const pushResult = await runGit(pushArgs, cwd)
325
+ if (!pushResult.ok) {
326
+ return {
327
+ ok: false,
328
+ error: "push_failed",
329
+ message: `Failed to push: ${pushResult.stderr}`
330
+ }
331
+ }
332
+
333
+ return {
334
+ ok: true,
335
+ pushed: {
336
+ remote,
337
+ branch,
338
+ force: !!args.force
339
+ },
340
+ output: pushResult.stdout,
341
+ message: `Pushed ${branch} to ${remote}${args.force ? " (forced)" : ""}`,
342
+ warning: args.force ? "Force push was used. This may have overwritten remote history." : undefined
343
+ }
344
+ }
345
+ }
346
+
347
+ // ============================================================================
348
+ // Tool: git_auto_stage - 自动暂存
349
+ // ============================================================================
350
+
351
+ export const gitAutoStageTool = {
352
+ name: "git_auto_stage",
353
+ description: "[FULL-AUTO MODE] Automatically stage files for commit. Available when git_auto.full_auto is enabled.",
354
+ inputSchema: {
355
+ type: "object",
356
+ properties: {
357
+ files: {
358
+ type: "array",
359
+ items: { type: "string" },
360
+ description: "Specific files to stage (default: all changes)"
361
+ },
362
+ all: {
363
+ type: "boolean",
364
+ description: "Stage all changes including untracked files (default: true if files not specified)"
365
+ }
366
+ },
367
+ required: []
368
+ },
369
+ async execute(args, ctx) {
370
+ const cwd = ctx.cwd || process.cwd()
371
+
372
+ // 检查全自动化模式
373
+ if (!isFullAutoMode(ctx.config)) {
374
+ return {
375
+ ok: false,
376
+ error: "full_auto_disabled",
377
+ message: "Full-auto mode is not enabled. Set git_auto.full_auto: true in your config."
378
+ }
379
+ }
380
+
381
+ if (!(await isGitRepo(cwd))) {
382
+ return {
383
+ ok: false,
384
+ error: "not_a_git_repo",
385
+ message: "Current directory is not a git repository"
386
+ }
387
+ }
388
+
389
+ const hasSpecificFiles = Array.isArray(args.files) && args.files.length > 0
390
+ const stageAll = !hasSpecificFiles && (args.all !== false)
391
+
392
+ let result
393
+ if (hasSpecificFiles) {
394
+ result = await runGit(["add", "--", ...args.files], cwd)
395
+ } else if (stageAll) {
396
+ result = await runGit(["add", "-A"], cwd)
397
+ } else {
398
+ return {
399
+ ok: false,
400
+ error: "nothing_to_stage",
401
+ message: "No files specified and all: false"
402
+ }
403
+ }
404
+
405
+ if (!result.ok) {
406
+ return {
407
+ ok: false,
408
+ error: "stage_failed",
409
+ message: result.stderr
410
+ }
411
+ }
412
+
413
+ // 获取 staged 文件列表
414
+ const diffResult = await runGit(["diff", "--staged", "--name-only"], cwd)
415
+ const stagedFiles = diffResult.ok
416
+ ? diffResult.stdout.split("\n").filter(Boolean)
417
+ : []
418
+
419
+ return {
420
+ ok: true,
421
+ staged: stagedFiles,
422
+ message: `Staged ${stagedFiles.length} file(s) for commit`
423
+ }
424
+ }
425
+ }
426
+
427
+ // ============================================================================
428
+ // Tool: git_full_auto_status - 获取全自动化模式状态
429
+ // ============================================================================
430
+
431
+ export const gitFullAutoStatusTool = {
432
+ name: "git_full_auto_status",
433
+ description: "Check the full-auto mode status and available operations. Shows current configuration and what operations are permitted.",
434
+ inputSchema: {
435
+ type: "object",
436
+ properties: {},
437
+ required: []
438
+ },
439
+ async execute(args, ctx) {
440
+ const cwd = ctx.cwd || process.cwd()
441
+ const policyMode = getPolicyMode(ctx.config)
442
+ const isGit = await isGitRepo(cwd)
443
+
444
+ return {
445
+ ok: true,
446
+ mode: policyMode.mode,
447
+ restrictions: policyMode.restrictions,
448
+ isGitRepo: isGit,
449
+ config: {
450
+ full_auto: ctx.config?.git_auto?.full_auto === true,
451
+ auto_commit: ctx.config?.git_auto?.auto_commit === true,
452
+ auto_push: ctx.config?.git_auto?.auto_push === true,
453
+ auto_stage: ctx.config?.git_auto?.auto_stage !== false,
454
+ allow_dangerous_ops: ctx.config?.git_auto?.allow_dangerous_ops === true
455
+ },
456
+ available_tools: [
457
+ ...(ctx.config?.git_auto?.full_auto ? ["git_auto_stage"] : []),
458
+ ...(ctx.config?.git_auto?.full_auto && ctx.config?.git_auto?.auto_commit ? ["git_auto_commit"] : []),
459
+ ...(ctx.config?.git_auto?.full_auto && ctx.config?.git_auto?.auto_push ? ["git_auto_push"] : []),
460
+ "git_snapshot",
461
+ "git_restore",
462
+ "git_info",
463
+ "git_status"
464
+ ]
465
+ }
466
+ }
467
+ }
468
+
469
+ // ============================================================================
470
+ // 导出所有全自动化工具
471
+ // ============================================================================
472
+
473
+ export const gitFullAutoTools = [
474
+ gitAutoCommitTool,
475
+ gitAutoPushTool,
476
+ gitAutoStageTool,
477
+ gitFullAutoStatusTool
478
+ ]