init claude-code

This commit is contained in:
2026-04-01 17:32:37 +02:00
commit 73b208c009
1902 changed files with 513237 additions and 0 deletions
@@ -0,0 +1,127 @@
import { z } from 'zod/v4'
import { getSessionId, setOriginalCwd } from '../../bootstrap/state.js'
import { clearSystemPromptSections } from '../../constants/systemPromptSections.js'
import { logEvent } from '../../services/analytics/index.js'
import type { Tool } from '../../Tool.js'
import { buildTool, type ToolDef } from '../../Tool.js'
import { clearMemoryFileCaches } from '../../utils/claudemd.js'
import { getCwd } from '../../utils/cwd.js'
import { findCanonicalGitRoot } from '../../utils/git.js'
import { lazySchema } from '../../utils/lazySchema.js'
import { getPlanSlug, getPlansDirectory } from '../../utils/plans.js'
import { setCwd } from '../../utils/Shell.js'
import { saveWorktreeState } from '../../utils/sessionStorage.js'
import {
createWorktreeForSession,
getCurrentWorktreeSession,
validateWorktreeSlug,
} from '../../utils/worktree.js'
import { ENTER_WORKTREE_TOOL_NAME } from './constants.js'
import { getEnterWorktreeToolPrompt } from './prompt.js'
import { renderToolResultMessage, renderToolUseMessage } from './UI.js'
const inputSchema = lazySchema(() =>
z.strictObject({
name: z
.string()
.superRefine((s, ctx) => {
try {
validateWorktreeSlug(s)
} catch (e) {
ctx.addIssue({ code: 'custom', message: (e as Error).message })
}
})
.optional()
.describe(
'Optional name for the worktree. Each "/"-separated segment may contain only letters, digits, dots, underscores, and dashes; max 64 chars total. A random name is generated if not provided.',
),
}),
)
type InputSchema = ReturnType<typeof inputSchema>
const outputSchema = lazySchema(() =>
z.object({
worktreePath: z.string(),
worktreeBranch: z.string().optional(),
message: z.string(),
}),
)
type OutputSchema = ReturnType<typeof outputSchema>
export type Output = z.infer<OutputSchema>
export const EnterWorktreeTool: Tool<InputSchema, Output> = buildTool({
name: ENTER_WORKTREE_TOOL_NAME,
searchHint: 'create an isolated git worktree and switch into it',
maxResultSizeChars: 100_000,
async description() {
return 'Creates an isolated worktree (via git or configured hooks) and switches the session into it'
},
async prompt() {
return getEnterWorktreeToolPrompt()
},
get inputSchema(): InputSchema {
return inputSchema()
},
get outputSchema(): OutputSchema {
return outputSchema()
},
userFacingName() {
return 'Creating worktree'
},
shouldDefer: true,
toAutoClassifierInput(input) {
return input.name ?? ''
},
renderToolUseMessage,
renderToolResultMessage,
async call(input) {
// Validate not already in a worktree created by this session
if (getCurrentWorktreeSession()) {
throw new Error('Already in a worktree session')
}
// Resolve to main repo root so worktree creation works from within a worktree
const mainRepoRoot = findCanonicalGitRoot(getCwd())
if (mainRepoRoot && mainRepoRoot !== getCwd()) {
process.chdir(mainRepoRoot)
setCwd(mainRepoRoot)
}
const slug = input.name ?? getPlanSlug()
const worktreeSession = await createWorktreeForSession(getSessionId(), slug)
process.chdir(worktreeSession.worktreePath)
setCwd(worktreeSession.worktreePath)
setOriginalCwd(getCwd())
saveWorktreeState(worktreeSession)
// Clear cached system prompt sections so env_info_simple recomputes with worktree context
clearSystemPromptSections()
// Clear memoized caches that depend on CWD
clearMemoryFileCaches()
getPlansDirectory.cache.clear?.()
logEvent('tengu_worktree_created', {
mid_session: true,
})
const branchInfo = worktreeSession.worktreeBranch
? ` on branch ${worktreeSession.worktreeBranch}`
: ''
return {
data: {
worktreePath: worktreeSession.worktreePath,
worktreeBranch: worktreeSession.worktreeBranch,
message: `Created worktree at ${worktreeSession.worktreePath}${branchInfo}. The session is now working in the worktree. Use ExitWorktree to leave mid-session, or exit the session to be prompted.`,
},
}
},
mapToolResultToToolResultBlockParam({ message }, toolUseID) {
return {
type: 'tool_result',
content: message,
tool_use_id: toolUseID,
}
},
} satisfies ToolDef<InputSchema, Output>)
+20
View File
@@ -0,0 +1,20 @@
import * as React from 'react';
import { Box, Text } from '../../ink.js';
import type { ToolProgressData } from '../../Tool.js';
import type { ProgressMessage } from '../../types/message.js';
import type { ThemeName } from '../../utils/theme.js';
import type { Output } from './EnterWorktreeTool.js';
export function renderToolUseMessage(): React.ReactNode {
return 'Creating worktree…';
}
export function renderToolResultMessage(output: Output, _progressMessagesForMessage: ProgressMessage<ToolProgressData>[], _options: {
theme: ThemeName;
}): React.ReactNode {
return <Box flexDirection="column">
<Text>
Switched to worktree on branch <Text bold>{output.worktreeBranch}</Text>
</Text>
<Text dimColor>{output.worktreePath}</Text>
</Box>;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIkJveCIsIlRleHQiLCJUb29sUHJvZ3Jlc3NEYXRhIiwiUHJvZ3Jlc3NNZXNzYWdlIiwiVGhlbWVOYW1lIiwiT3V0cHV0IiwicmVuZGVyVG9vbFVzZU1lc3NhZ2UiLCJSZWFjdE5vZGUiLCJyZW5kZXJUb29sUmVzdWx0TWVzc2FnZSIsIm91dHB1dCIsIl9wcm9ncmVzc01lc3NhZ2VzRm9yTWVzc2FnZSIsIl9vcHRpb25zIiwidGhlbWUiLCJ3b3JrdHJlZUJyYW5jaCIsIndvcmt0cmVlUGF0aCJdLCJzb3VyY2VzIjpbIlVJLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBSZWFjdCBmcm9tICdyZWFjdCdcbmltcG9ydCB7IEJveCwgVGV4dCB9IGZyb20gJy4uLy4uL2luay5qcydcbmltcG9ydCB0eXBlIHsgVG9vbFByb2dyZXNzRGF0YSB9IGZyb20gJy4uLy4uL1Rvb2wuanMnXG5pbXBvcnQgdHlwZSB7IFByb2dyZXNzTWVzc2FnZSB9IGZyb20gJy4uLy4uL3R5cGVzL21lc3NhZ2UuanMnXG5pbXBvcnQgdHlwZSB7IFRoZW1lTmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzL3RoZW1lLmpzJ1xuaW1wb3J0IHR5cGUgeyBPdXRwdXQgfSBmcm9tICcuL0VudGVyV29ya3RyZWVUb29sLmpzJ1xuXG5leHBvcnQgZnVuY3Rpb24gcmVuZGVyVG9vbFVzZU1lc3NhZ2UoKTogUmVhY3QuUmVhY3ROb2RlIHtcbiAgcmV0dXJuICdDcmVhdGluZyB3b3JrdHJlZeKApidcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlbmRlclRvb2xSZXN1bHRNZXNzYWdlKFxuICBvdXRwdXQ6IE91dHB1dCxcbiAgX3Byb2dyZXNzTWVzc2FnZXNGb3JNZXNzYWdlOiBQcm9ncmVzc01lc3NhZ2U8VG9vbFByb2dyZXNzRGF0YT5bXSxcbiAgX29wdGlvbnM6IHsgdGhlbWU6IFRoZW1lTmFtZSB9LFxuKTogUmVhY3QuUmVhY3ROb2RlIHtcbiAgcmV0dXJuIChcbiAgICA8Qm94IGZsZXhEaXJlY3Rpb249XCJjb2x1bW5cIj5cbiAgICAgIDxUZXh0PlxuICAgICAgICBTd2l0Y2hlZCB0byB3b3JrdHJlZSBvbiBicmFuY2ggPFRleHQgYm9sZD57b3V0cHV0Lndvcmt0cmVlQnJhbmNofTwvVGV4dD5cbiAgICAgIDwvVGV4dD5cbiAgICAgIDxUZXh0IGRpbUNvbG9yPntvdXRwdXQud29ya3RyZWVQYXRofTwvVGV4dD5cbiAgICA8L0JveD5cbiAgKVxufVxuIl0sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUtBLEtBQUssTUFBTSxPQUFPO0FBQzlCLFNBQVNDLEdBQUcsRUFBRUMsSUFBSSxRQUFRLGNBQWM7QUFDeEMsY0FBY0MsZ0JBQWdCLFFBQVEsZUFBZTtBQUNyRCxjQUFjQyxlQUFlLFFBQVEsd0JBQXdCO0FBQzdELGNBQWNDLFNBQVMsUUFBUSxzQkFBc0I7QUFDckQsY0FBY0MsTUFBTSxRQUFRLHdCQUF3QjtBQUVwRCxPQUFPLFNBQVNDLG9CQUFvQkEsQ0FBQSxDQUFFLEVBQUVQLEtBQUssQ0FBQ1EsU0FBUyxDQUFDO0VBQ3RELE9BQU8sb0JBQW9CO0FBQzdCO0FBRUEsT0FBTyxTQUFTQyx1QkFBdUJBLENBQ3JDQyxNQUFNLEVBQUVKLE1BQU0sRUFDZEssMkJBQTJCLEVBQUVQLGVBQWUsQ0FBQ0QsZ0JBQWdCLENBQUMsRUFBRSxFQUNoRVMsUUFBUSxFQUFFO0VBQUVDLEtBQUssRUFBRVIsU0FBUztBQUFDLENBQUMsQ0FDL0IsRUFBRUwsS0FBSyxDQUFDUSxTQUFTLENBQUM7RUFDakIsT0FDRSxDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUMsUUFBUTtBQUMvQixNQUFNLENBQUMsSUFBSTtBQUNYLHVDQUF1QyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQ0UsTUFBTSxDQUFDSSxjQUFjLENBQUMsRUFBRSxJQUFJO0FBQy9FLE1BQU0sRUFBRSxJQUFJO0FBQ1osTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQ0osTUFBTSxDQUFDSyxZQUFZLENBQUMsRUFBRSxJQUFJO0FBQ2hELElBQUksRUFBRSxHQUFHLENBQUM7QUFFViIsImlnbm9yZUxpc3QiOltdfQ==
+1
View File
@@ -0,0 +1 @@
export const ENTER_WORKTREE_TOOL_NAME = 'EnterWorktree'
+30
View File
@@ -0,0 +1,30 @@
export function getEnterWorktreeToolPrompt(): string {
return `Use this tool ONLY when the user explicitly asks to work in a worktree. This tool creates an isolated git worktree and switches the current session into it.
## When to Use
- The user explicitly says "worktree" (e.g., "start a worktree", "work in a worktree", "create a worktree", "use a worktree")
## When NOT to Use
- The user asks to create a branch, switch branches, or work on a different branch — use git commands instead
- The user asks to fix a bug or work on a feature — use normal git workflow unless they specifically mention worktrees
- Never use this tool unless the user explicitly mentions "worktree"
## Requirements
- Must be in a git repository, OR have WorktreeCreate/WorktreeRemove hooks configured in settings.json
- Must not already be in a worktree
## Behavior
- In a git repository: creates a new git worktree inside \`.claude/worktrees/\` with a new branch based on HEAD
- Outside a git repository: delegates to WorktreeCreate/WorktreeRemove hooks for VCS-agnostic isolation
- Switches the session's working directory to the new worktree
- Use ExitWorktree to leave the worktree mid-session (keep or remove). On session exit, if still in the worktree, the user will be prompted to keep or remove it
## Parameters
- \`name\` (optional): A name for the worktree. If not provided, a random name is generated.
`
}