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
+67
View File
@@ -0,0 +1,67 @@
import { queryHaiku } from '../../services/api/claude.js'
import type { Message } from '../../types/message.js'
import { logForDebugging } from '../../utils/debug.js'
import { errorMessage } from '../../utils/errors.js'
import { safeParseJSON } from '../../utils/json.js'
import { extractTextContent } from '../../utils/messages.js'
import { extractConversationText } from '../../utils/sessionTitle.js'
import { asSystemPrompt } from '../../utils/systemPromptType.js'
export async function generateSessionName(
messages: Message[],
signal: AbortSignal,
): Promise<string | null> {
const conversationText = extractConversationText(messages)
if (!conversationText) {
return null
}
try {
const result = await queryHaiku({
systemPrompt: asSystemPrompt([
'Generate a short kebab-case name (2-4 words) that captures the main topic of this conversation. Use lowercase words separated by hyphens. Examples: "fix-login-bug", "add-auth-feature", "refactor-api-client", "debug-test-failures". Return JSON with a "name" field.',
]),
userPrompt: conversationText,
outputFormat: {
type: 'json_schema',
schema: {
type: 'object',
properties: {
name: { type: 'string' },
},
required: ['name'],
additionalProperties: false,
},
},
signal,
options: {
querySource: 'rename_generate_name',
agents: [],
isNonInteractiveSession: false,
hasAppendSystemPrompt: false,
mcpTools: [],
},
})
const content = extractTextContent(result.message.content)
const response = safeParseJSON(content)
if (
response &&
typeof response === 'object' &&
'name' in response &&
typeof (response as { name: unknown }).name === 'string'
) {
return (response as { name: string }).name
}
return null
} catch (error) {
// Haiku timeout/rate-limit/network are expected operational failures —
// logForDebugging, not logError. Called automatically on every 3rd bridge
// message (initReplBridge.ts), so errors here would flood the error file.
logForDebugging(`generateSessionName failed: ${errorMessage(error)}`, {
level: 'error',
})
return null
}
}
+12
View File
@@ -0,0 +1,12 @@
import type { Command } from '../../commands.js'
const rename = {
type: 'local-jsx',
name: 'rename',
description: 'Rename the current conversation',
immediate: true,
argumentHint: '[name]',
load: () => import('./rename.js'),
} satisfies Command
export default rename
+87
View File
@@ -0,0 +1,87 @@
import type { UUID } from 'crypto'
import { getSessionId } from '../../bootstrap/state.js'
import {
getBridgeBaseUrlOverride,
getBridgeTokenOverride,
} from '../../bridge/bridgeConfig.js'
import type { ToolUseContext } from '../../Tool.js'
import type {
LocalJSXCommandContext,
LocalJSXCommandOnDone,
} from '../../types/command.js'
import { getMessagesAfterCompactBoundary } from '../../utils/messages.js'
import {
getTranscriptPath,
saveAgentName,
saveCustomTitle,
} from '../../utils/sessionStorage.js'
import { isTeammate } from '../../utils/teammate.js'
import { generateSessionName } from './generateSessionName.js'
export async function call(
onDone: LocalJSXCommandOnDone,
context: ToolUseContext & LocalJSXCommandContext,
args: string,
): Promise<null> {
// Prevent teammates from renaming - their names are set by team leader
if (isTeammate()) {
onDone(
'Cannot rename: This session is a swarm teammate. Teammate names are set by the team leader.',
{ display: 'system' },
)
return null
}
let newName: string
if (!args || args.trim() === '') {
const generated = await generateSessionName(
getMessagesAfterCompactBoundary(context.messages),
context.abortController.signal,
)
if (!generated) {
onDone(
'Could not generate a name: no conversation context yet. Usage: /rename <name>',
{ display: 'system' },
)
return null
}
newName = generated
} else {
newName = args.trim()
}
const sessionId = getSessionId() as UUID
const fullPath = getTranscriptPath()
// Always save the custom title (session name)
await saveCustomTitle(sessionId, newName, fullPath)
// Sync title to bridge session on claude.ai/code (best-effort, non-blocking).
// v2 env-less bridge stores cse_* in replBridgeSessionId —
// updateBridgeSessionTitle retags internally for the compat endpoint.
const appState = context.getAppState()
const bridgeSessionId = appState.replBridgeSessionId
if (bridgeSessionId) {
const tokenOverride = getBridgeTokenOverride()
void import('../../bridge/createSession.js').then(
({ updateBridgeSessionTitle }) =>
updateBridgeSessionTitle(bridgeSessionId, newName, {
baseUrl: getBridgeBaseUrlOverride(),
getAccessToken: tokenOverride ? () => tokenOverride : undefined,
}).catch(() => {}),
)
}
// Also persist as the session's agent name for prompt-bar display
await saveAgentName(sessionId, newName, fullPath)
context.setAppState(prev => ({
...prev,
standaloneAgentContext: {
...prev.standaloneAgentContext,
name: newName,
},
}))
onDone(`Session renamed to: ${newName}`, { display: 'system' })
return null
}