/ src / commands / commit.ts
commit.ts
 1  import type { Command } from '../commands.js'
 2  import { getAttributionTexts } from '../utils/attribution.js'
 3  import { executeShellCommandsInPrompt } from '../utils/promptShellExecution.js'
 4  import { getUndercoverInstructions, isUndercover } from '../utils/undercover.js'
 5  
 6  const ALLOWED_TOOLS = [
 7    'Bash(git add:*)',
 8    'Bash(git status:*)',
 9    'Bash(git commit:*)',
10  ]
11  
12  function getPromptContent(): string {
13    const { commit: commitAttribution } = getAttributionTexts()
14  
15    let prefix = ''
16    if (process.env.USER_TYPE === 'ant' && isUndercover()) {
17      prefix = getUndercoverInstructions() + '\n'
18    }
19  
20    return `${prefix}## Context
21  
22  - Current git status: !\`git status\`
23  - Current git diff (staged and unstaged changes): !\`git diff HEAD\`
24  - Current branch: !\`git branch --show-current\`
25  - Recent commits: !\`git log --oneline -10\`
26  
27  ## Git Safety Protocol
28  
29  - NEVER update the git config
30  - NEVER skip hooks (--no-verify, --no-gpg-sign, etc) unless the user explicitly requests it
31  - CRITICAL: ALWAYS create NEW commits. NEVER use git commit --amend, unless the user explicitly requests it
32  - Do not commit files that likely contain secrets (.env, credentials.json, etc). Warn the user if they specifically request to commit those files
33  - If there are no changes to commit (i.e., no untracked files and no modifications), do not create an empty commit
34  - Never use git commands with the -i flag (like git rebase -i or git add -i) since they require interactive input which is not supported
35  
36  ## Your task
37  
38  Based on the above changes, create a single git commit:
39  
40  1. Analyze all staged changes and draft a commit message:
41     - Look at the recent commits above to follow this repository's commit message style
42     - Summarize the nature of the changes (new feature, enhancement, bug fix, refactoring, test, docs, etc.)
43     - Ensure the message accurately reflects the changes and their purpose (i.e. "add" means a wholly new feature, "update" means an enhancement to an existing feature, "fix" means a bug fix, etc.)
44     - Draft a concise (1-2 sentences) commit message that focuses on the "why" rather than the "what"
45  
46  2. Stage relevant files and create the commit using HEREDOC syntax:
47  \`\`\`
48  git commit -m "$(cat <<'EOF'
49  Commit message here.${commitAttribution ? `\n\n${commitAttribution}` : ''}
50  EOF
51  )"
52  \`\`\`
53  
54  You have the capability to call multiple tools in a single response. Stage and create the commit using a single message. Do not use any other tools or do anything else. Do not send any other text or messages besides these tool calls.`
55  }
56  
57  const command = {
58    type: 'prompt',
59    name: 'commit',
60    description: 'Create a git commit',
61    allowedTools: ALLOWED_TOOLS,
62    contentLength: 0, // Dynamic content
63    progressMessage: 'creating commit',
64    source: 'builtin',
65    async getPromptForCommand(_args, context) {
66      const promptContent = getPromptContent()
67      const finalContent = await executeShellCommandsInPrompt(
68        promptContent,
69        {
70          ...context,
71          getAppState() {
72            const appState = context.getAppState()
73            return {
74              ...appState,
75              toolPermissionContext: {
76                ...appState.toolPermissionContext,
77                alwaysAllowRules: {
78                  ...appState.toolPermissionContext.alwaysAllowRules,
79                  command: ALLOWED_TOOLS,
80                },
81              },
82            }
83          },
84        },
85        '/commit',
86      )
87  
88      return [{ type: 'text', text: finalContent }]
89    },
90  } satisfies Command
91  
92  export default command