tagteam 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +101 -0
- package/dist/index.js +1326 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/ui.tsx","../src/agents/claude.ts","../src/agents/codex.ts","../src/format.ts","../src/clipboard.ts","../src/db/index.ts","../src/db/sessions.ts","../src/db/messages.ts","../src/prompts.ts","../src/config-editor.tsx"],"sourcesContent":["import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { loadConfig, setConfigValue } from \"./config.js\";\nimport { startApp, showTranscript, showTranscriptMarkdown, showSessionList } from \"./ui.js\";\nimport { startConfigEditor } from \"./config-editor.js\";\nimport {\n getMostRecentSession,\n getSession,\n getSessionByPrefix,\n listSessions,\n} from \"./db/sessions.js\";\nimport { getMessages } from \"./db/messages.js\";\nimport { closeDb } from \"./db/index.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"tagteam\")\n .description(\"Tag Team - Orchestrate Claude and Codex collaboratively\")\n .version(\"0.1.0\")\n .option(\"--claude-model <model>\", \"Claude model to use\")\n .option(\"--codex-model <model>\", \"Codex model to use\")\n .argument(\"[prompt...]\", \"Prompt to send to both agents\")\n .action(async (promptParts: string[], opts) => {\n const config = loadConfig();\n const prompt = promptParts.join(\" \") || undefined;\n\n const instance = startApp({\n initialPrompt: prompt,\n claudeModel: opts.claudeModel ?? config.claude.model,\n codexModel: opts.codexModel ?? config.codex.model,\n config,\n });\n\n await instance.waitUntilExit();\n });\n\n// Discuss - auto-loop until consensus\nprogram\n .command(\"discuss\")\n .description(\"Have Claude and Codex discuss a topic until they reach consensus\")\n .argument(\"<prompt...>\", \"Topic to discuss\")\n .action(async (promptParts: string[]) => {\n const config = loadConfig();\n const prompt = promptParts.join(\" \");\n\n const instance = startApp({\n initialPrompt: prompt,\n claudeModel: config.claude.model,\n codexModel: config.codex.model,\n config,\n discuss: true,\n });\n\n await instance.waitUntilExit();\n });\n\n// Continue most recent session\nprogram\n .command(\"continue\")\n .description(\"Resume the most recent session\")\n .action(async () => {\n const config = loadConfig();\n const session = getMostRecentSession();\n\n if (!session) {\n console.log(chalk.red(\" No active sessions found.\"));\n process.exit(1);\n }\n\n const dbMessages = getMessages(session.id);\n const transcript = dbMessages.map((m) => ({\n role: m.role as \"user\" | \"claude\" | \"codex\" | \"system\",\n content: m.content,\n round: m.round,\n }));\n\n const instance = startApp({\n sessionId: session.id,\n claudeModel: config.claude.model,\n codexModel: config.codex.model,\n config,\n showTranscript: transcript,\n });\n\n await instance.waitUntilExit();\n });\n\n// Resume a specific session\nprogram\n .command(\"resume [id]\")\n .description(\"Resume a session by ID, or pick interactively\")\n .action(async (id: string | undefined) => {\n const config = loadConfig();\n\n if (!id) {\n const sessions = listSessions(20);\n if (sessions.length === 0) {\n console.log(chalk.red(\" No sessions found.\"));\n process.exit(1);\n }\n\n console.log(chalk.bold(\"\\n Recent sessions:\\n\"));\n sessions.forEach((s, i) => {\n const sid = chalk.cyan(s.id.slice(0, 7));\n const title = s.title || chalk.dim(\"(untitled)\");\n const date = chalk.dim(s.updated_at);\n console.log(` ${chalk.dim(`${i + 1}.`)} ${sid} ${title} ${date}`);\n });\n console.log();\n\n const readline = await import(\"node:readline\");\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise<void>((resolve) => {\n rl.question(\" Select session number: \", async (input) => {\n rl.close();\n const num = parseInt(input.trim(), 10);\n if (isNaN(num) || num < 1 || num > sessions.length) {\n console.log(chalk.red(\" Invalid selection.\"));\n closeDb();\n resolve();\n return;\n }\n\n const session = sessions[num - 1];\n const dbMessages = getMessages(session.id);\n const transcript = dbMessages.map((m) => ({\n role: m.role as \"user\" | \"claude\" | \"codex\" | \"system\",\n content: m.content,\n round: m.round,\n }));\n\n const instance = startApp({\n sessionId: session.id,\n claudeModel: config.claude.model,\n codexModel: config.codex.model,\n config,\n showTranscript: transcript,\n });\n\n await instance.waitUntilExit();\n resolve();\n });\n });\n }\n\n const session = getSession(id) || getSessionByPrefix(id);\n if (!session) {\n console.log(chalk.red(` Session not found: ${id}`));\n process.exit(1);\n }\n\n const dbMessages = getMessages(session.id);\n const transcript = dbMessages.map((m) => ({\n role: m.role as \"user\" | \"claude\" | \"codex\" | \"system\",\n content: m.content,\n round: m.round,\n }));\n\n const instance = startApp({\n sessionId: session.id,\n claudeModel: config.claude.model,\n codexModel: config.codex.model,\n config,\n showTranscript: transcript,\n });\n\n await instance.waitUntilExit();\n });\n\n// History\nprogram\n .command(\"history\")\n .description(\"List recent sessions\")\n .option(\"-n, --limit <n>\", \"Number of sessions to show\", parseInt, 20)\n .action((opts) => {\n const sessions = listSessions(opts.limit);\n console.log(chalk.bold(\"\\n Recent sessions:\\n\"));\n showSessionList(sessions);\n console.log();\n closeDb();\n });\n\n// Show transcript\nprogram\n .command(\"show <id>\")\n .description(\"Print full transcript for a session\")\n .option(\"-m, --markdown\", \"Output as GitHub-compatible markdown\")\n .action((id: string, opts: { markdown?: boolean }) => {\n const session = getSession(id) || getSessionByPrefix(id);\n if (!session) {\n console.log(chalk.red(` Session not found: ${id}`));\n process.exit(1);\n }\n\n if (opts.markdown) {\n process.stdout.write(showTranscriptMarkdown(session.id));\n } else {\n showTranscript(session.id);\n }\n closeDb();\n });\n\n// Config commands\nconst configCmd = program\n .command(\"config\")\n .description(\"Manage configuration\")\n .action(async () => {\n const instance = startConfigEditor();\n await instance.waitUntilExit();\n });\n\nconfigCmd\n .command(\"edit\")\n .description(\"Interactively edit configuration\")\n .action(async () => {\n const instance = startConfigEditor();\n await instance.waitUntilExit();\n });\n\nconfigCmd\n .command(\"show\")\n .description(\"Show current configuration\")\n .action(() => {\n const config = loadConfig();\n console.log(chalk.bold(\"\\n Configuration:\\n\"));\n console.log(\n chalk.dim(\" claude.model = \") + chalk.white(config.claude.model)\n );\n console.log(\n chalk.dim(\" codex.model = \") + chalk.white(config.codex.model)\n );\n console.log(\n chalk.dim(\" discussion.max_rounds = \") + chalk.white(String(config.discussion.max_rounds))\n );\n console.log();\n });\n\nconfigCmd\n .command(\"set <key> <value>\")\n .description(\"Set a configuration value\")\n .action((key: string, value: string) => {\n try {\n setConfigValue(key, value);\n console.log(chalk.green(` Set ${key} = ${value}`));\n } catch (e: any) {\n console.log(chalk.red(` ${e.message}`));\n process.exit(1);\n }\n });\n\nprogram.parseAsync();\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { parse, stringify } from \"smol-toml\";\n\nexport interface TagTeamConfig {\n claude: {\n model: string;\n };\n codex: {\n model: string;\n };\n discussion: {\n max_rounds: number;\n };\n}\n\nconst DEFAULT_CONFIG: TagTeamConfig = {\n claude: {\n model: \"sonnet\",\n },\n codex: {\n model: \"gpt-5.3-codex\",\n },\n discussion: {\n max_rounds: 10,\n },\n};\n\nexport function getConfigDir(): string {\n return join(homedir(), \".tagteam\");\n}\n\nexport function getConfigPath(): string {\n return join(getConfigDir(), \"config.toml\");\n}\n\nexport function ensureConfigDir(): void {\n const dir = getConfigDir();\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n}\n\nexport function loadConfig(): TagTeamConfig {\n const configPath = getConfigPath();\n\n if (!existsSync(configPath)) {\n return { ...DEFAULT_CONFIG };\n }\n\n try {\n const raw = readFileSync(configPath, \"utf-8\");\n const parsed = parse(raw) as any;\n return {\n claude: { ...DEFAULT_CONFIG.claude, ...parsed.claude },\n codex: { ...DEFAULT_CONFIG.codex, ...parsed.codex },\n discussion: { ...DEFAULT_CONFIG.discussion, ...parsed.discussion },\n };\n } catch {\n return { ...DEFAULT_CONFIG };\n }\n}\n\nexport function saveConfig(config: TagTeamConfig): void {\n ensureConfigDir();\n const configPath = getConfigPath();\n writeFileSync(configPath, stringify(config as any), \"utf-8\");\n}\n\nexport function setConfigValue(\n key: string,\n value: string\n): TagTeamConfig {\n const config = loadConfig();\n const parts = key.split(\".\");\n\n if (parts.length === 1) {\n switch (parts[0]) {\n case \"claude_model\":\n config.claude.model = value;\n break;\n case \"codex_model\":\n config.codex.model = value;\n break;\n case \"discussion_max_rounds\":\n config.discussion.max_rounds = Number(value);\n break;\n default:\n throw new Error(`Unknown config key: ${key}`);\n }\n } else if (parts.length === 2) {\n const [section, field] = parts;\n if (section === \"claude\" && field === \"model\") {\n config.claude.model = value;\n } else if (section === \"codex\" && field === \"model\") {\n config.codex.model = value;\n } else if (section === \"discussion\" && field === \"max_rounds\") {\n config.discussion.max_rounds = Number(value);\n } else {\n throw new Error(`Unknown config key: ${key}`);\n }\n } else {\n throw new Error(`Invalid config key format: ${key}`);\n }\n\n saveConfig(config);\n return config;\n}\n","import React, { useState, useEffect, useCallback, useRef } from \"react\";\nimport { render, Box, Text, useApp, useInput } from \"ink\";\nimport TextInput from \"ink-text-input\";\nimport Spinner from \"ink-spinner\";\nimport { marked } from \"marked\";\nimport { markedTerminal } from \"marked-terminal\";\nimport { nanoid } from \"nanoid\";\nimport { runClaude } from \"./agents/claude.js\";\nimport { runCodex } from \"./agents/codex.js\";\nimport type { AgentName } from \"./agents/types.js\";\nimport { formatAsMarkdown } from \"./format.js\";\nimport { copyToClipboard } from \"./clipboard.js\";\nimport { createSession, touchSession, updateSessionTitle } from \"./db/sessions.js\";\nimport { insertMessage, getMessages, deleteMessagesFromRound } from \"./db/messages.js\";\nimport { closeDb } from \"./db/index.js\";\nimport {\n collaborationPrompt,\n discussionPrompt,\n debatePrompt,\n debateRoundPrompt,\n CONSENSUS_MARKER,\n formatConversationHistory,\n} from \"./prompts.js\";\nimport type { TagTeamConfig } from \"./config.js\";\nimport { InlineConfigEditor } from \"./config-editor.js\";\n\nmarked.use(markedTerminal() as any);\n\n// --- Types ---\n\ninterface Message {\n role: \"user\" | \"claude\" | \"codex\" | \"system\";\n content: string;\n round: number;\n error?: boolean;\n}\n\ninterface AppProps {\n initialPrompt?: string;\n sessionId?: string;\n claudeModel: string;\n codexModel: string;\n config: TagTeamConfig;\n showTranscript?: Message[];\n discuss?: boolean;\n}\n\ntype AppState = \"input\" | \"running\" | \"done\" | \"config\";\ntype Target = \"both\" | \"claude\" | \"codex\";\n\ninterface ParsedInput {\n target: Target;\n prompt: string;\n discuss: boolean;\n}\n\nfunction parseInput(input: string): ParsedInput {\n const lower = input.toLowerCase();\n if (lower.startsWith(\"discuss \")) {\n return { target: \"both\", prompt: input.slice(8).trim(), discuss: true };\n }\n if (lower.startsWith(\"claude \") || lower.startsWith(\"claude, \")) {\n return { target: \"claude\", prompt: input.slice(input.indexOf(\" \") + 1).trim(), discuss: false };\n }\n if (lower.startsWith(\"codex \") || lower.startsWith(\"codex, \")) {\n return { target: \"codex\", prompt: input.slice(input.indexOf(\" \") + 1).trim(), discuss: false };\n }\n return { target: \"both\", prompt: input, discuss: false };\n}\n\n// --- Components ---\n\nfunction RenderedMarkdown({ text }: { text: string }) {\n const rendered = (marked.parse(text) as string).trimEnd();\n return <Text>{rendered}</Text>;\n}\n\nfunction AgentResponseBlock({\n agent,\n content,\n error,\n}: {\n agent: AgentName;\n content: string;\n error?: boolean;\n}) {\n const color = agent === \"claude\" ? \"magenta\" : \"green\";\n\n if (error) {\n return (\n <Box flexDirection=\"column\" marginLeft={1} marginBottom={1}>\n <Text color=\"red\" bold>\n {agent === \"claude\" ? \"Claude\" : \"Codex\"} error:\n </Text>\n <Box marginLeft={1}>\n <Text color=\"red\">{content}</Text>\n </Box>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" marginLeft={1} marginBottom={1}>\n <Text color={color} bold>\n {agent === \"claude\" ? \"Claude\" : \"Codex\"}:\n </Text>\n <Box marginLeft={1}>\n <RenderedMarkdown text={content} />\n </Box>\n </Box>\n );\n}\n\nfunction Header({ sessionId }: { sessionId: string }) {\n return (\n <Box marginBottom={1}>\n <Text dimColor>{\"── \"}</Text>\n <Text bold>Tag Team</Text>\n <Text dimColor>{\" ── session \"}</Text>\n <Text color=\"cyan\">{sessionId.slice(0, 7)}</Text>\n <Text dimColor>{\" \" + \"─\".repeat(35)}</Text>\n </Box>\n );\n}\n\nfunction UserMessage({ content }: { content: string }) {\n return (\n <Box marginLeft={1} marginBottom={1}>\n <Text bold color=\"white\">\n You:{\" \"}\n </Text>\n <Text>{content}</Text>\n </Box>\n );\n}\n\nfunction ThinkingIndicator({ agent }: { agent: AgentName }) {\n const color = agent === \"claude\" ? \"magenta\" : \"green\";\n const label = agent === \"claude\" ? \"Claude\" : \"Codex\";\n return (\n <Box marginLeft={1}>\n <Text color={color}>\n <Spinner type=\"dots\" />\n </Text>\n <Text color={color}> {label} is thinking...</Text>\n </Box>\n );\n}\n\nfunction DiscussionStatus({ round, maxRounds }: { round: number; maxRounds: number }) {\n return (\n <Box marginLeft={1} marginBottom={1}>\n <Text color=\"yellow\" bold>\n Discussion round {round}/{maxRounds}\n </Text>\n </Box>\n );\n}\n\nfunction ConsensusReached() {\n return (\n <Box marginLeft={1} marginBottom={1}>\n <Text color=\"green\" bold>\n Consensus reached.\n </Text>\n </Box>\n );\n}\n\nfunction PromptInput({\n onSubmit,\n}: {\n onSubmit: (value: string) => void;\n}) {\n const [value, setValue] = useState(\"\");\n\n const handleSubmit = useCallback(\n (submitted: string) => {\n if (submitted.trim()) {\n onSubmit(submitted.trim());\n setValue(\"\");\n }\n },\n [onSubmit]\n );\n\n return (\n <Box marginLeft={1}>\n <Text bold color=\"white\">\n {\"> \"}\n </Text>\n <TextInput\n value={value}\n onChange={setValue}\n onSubmit={handleSubmit}\n showCursor\n />\n </Box>\n );\n}\n\n// --- Main App ---\n\nfunction App({\n initialPrompt,\n sessionId: existingSessionId,\n claudeModel,\n codexModel,\n config,\n showTranscript,\n discuss: initialDiscuss,\n}: AppProps) {\n const { exit } = useApp();\n const [sessionId, setSessionId] = useState(() => existingSessionId ?? nanoid(12));\n const [messages, setMessages] = useState<Message[]>(showTranscript ?? []);\n const [state, setState] = useState<AppState>(\n initialPrompt ? \"running\" : \"input\"\n );\n const [thinkingAgents, setThinkingAgents] = useState<AgentName[]>([]);\n const [discussionRound, setDiscussionRound] = useState(0);\n const [consensusReached, setConsensusReached] = useState(false);\n const [statusMessage, setStatusMessage] = useState<string | null>(null);\n const [roundNum, setRoundNum] = useState(() => {\n if (showTranscript && showTranscript.length > 0) {\n return Math.max(...showTranscript.map((m) => m.round)) + 1;\n }\n return 0;\n });\n\n // Create session on first mount if new\n useEffect(() => {\n if (!existingSessionId) {\n createSession(sessionId, process.cwd());\n }\n }, []);\n\n // Handle initial prompt\n useEffect(() => {\n if (initialPrompt && state === \"running\") {\n if (initialDiscuss) {\n runDiscussion(initialPrompt);\n } else {\n runRound(initialPrompt);\n }\n }\n }, []);\n\n const abortRef = useRef<AbortController | null>(null);\n const runningRoundRef = useRef<number | null>(null);\n\n // Ctrl+C and Escape handling\n useInput((input, key) => {\n if (key.ctrl && input === \"c\") {\n abortRef.current?.abort();\n closeDb();\n exit();\n }\n if (key.escape && state === \"running\") {\n abortRef.current?.abort();\n abortRef.current = null;\n\n // Remove the user prompt and any partial results from DB and state\n if (runningRoundRef.current !== null) {\n deleteMessagesFromRound(sessionId, runningRoundRef.current);\n const fromRound = runningRoundRef.current;\n setMessages((prev) => prev.filter((m) => m.round < fromRound));\n runningRoundRef.current = null;\n }\n\n setThinkingAgents([]);\n setDiscussionRound(0);\n setStatusMessage(\"Interrupted.\");\n setState(\"input\");\n }\n });\n\n // Run both agents, save results, return new messages\n const runAgents = async (\n currentMessages: Message[],\n round: number,\n target: Target,\n promptOverride?: string,\n isDebate = false,\n ): Promise<Message[]> => {\n const runCl = target === \"both\" || target === \"claude\";\n const runCx = target === \"both\" || target === \"codex\";\n\n const activeAgents: AgentName[] = [];\n if (runCl) activeAgents.push(\"claude\");\n if (runCx) activeAgents.push(\"codex\");\n setThinkingAgents(activeAgents);\n\n const history = formatConversationHistory(\n currentMessages.map((m) => ({\n role: m.role,\n agent:\n m.role === \"claude\" || m.role === \"codex\"\n ? (m.role as AgentName)\n : undefined,\n content: m.content,\n }))\n );\n\n const cwd = process.cwd();\n const isFirstRound = round === 0 && !existingSessionId;\n\n const agentPrompt = (agent: AgentName) => {\n if (promptOverride) return promptOverride;\n if (isFirstRound && target === \"both\") {\n return currentMessages[currentMessages.length - 1]?.content || \"\";\n }\n return \"Provide your response for this round.\";\n };\n\n const agentSystemPrompt = (agent: AgentName) => {\n if (isDebate) {\n if (isFirstRound) return debatePrompt(agent);\n return debateRoundPrompt(agent, history);\n }\n if (isFirstRound && target === \"both\") return collaborationPrompt(agent);\n return discussionPrompt(agent, history);\n };\n\n const ac = new AbortController();\n abortRef.current = ac;\n\n const results: Array<{ agent: AgentName; result: PromiseSettledResult<Awaited<ReturnType<typeof runClaude>>> }> = [];\n const promises: Array<Promise<void>> = [];\n\n if (runCl) {\n promises.push(\n runClaude({\n prompt: agentPrompt(\"claude\"),\n systemPrompt: agentSystemPrompt(\"claude\"),\n model: claudeModel,\n cwd,\n signal: ac.signal,\n }).then(\n (value) => { results.push({ agent: \"claude\", result: { status: \"fulfilled\", value } }); },\n (reason) => { results.push({ agent: \"claude\", result: { status: \"rejected\", reason } }); }\n )\n );\n }\n if (runCx) {\n promises.push(\n runCodex({\n prompt: agentPrompt(\"codex\"),\n systemPrompt: agentSystemPrompt(\"codex\"),\n model: codexModel,\n cwd,\n signal: ac.signal,\n }).then(\n (value) => { results.push({ agent: \"codex\", result: { status: \"fulfilled\", value } }); },\n (reason) => { results.push({ agent: \"codex\", result: { status: \"rejected\", reason } }); }\n )\n );\n }\n\n await Promise.all(promises);\n abortRef.current = null;\n\n // If aborted, bail out — the Escape handler already reset UI state\n if (ac.signal.aborted) return [];\n\n setThinkingAgents([]);\n\n const newMessages: Message[] = [];\n\n for (const { agent, result } of results) {\n if (result.status === \"fulfilled\") {\n const resp = result.value;\n const msg: Message = {\n role: agent,\n content: resp.error || resp.text,\n round,\n error: !!resp.error,\n };\n newMessages.push(msg);\n insertMessage({\n sessionId,\n role: agent,\n content: resp.error || resp.text,\n round,\n durationMs: resp.durationMs,\n });\n } else {\n const errorMsg = result.reason?.message || \"Failed to run\";\n const msg: Message = {\n role: agent,\n content: errorMsg,\n round,\n error: true,\n };\n newMessages.push(msg);\n insertMessage({\n sessionId,\n role: agent,\n content: `[Error: ${errorMsg}]`,\n round,\n });\n }\n }\n\n return newMessages;\n };\n\n const runRound = async (rawInput: string) => {\n const { target, prompt, discuss } = parseInput(rawInput);\n\n if (discuss) {\n return runDiscussion(prompt);\n }\n\n const currentRound = roundNum;\n runningRoundRef.current = currentRound;\n\n // Add user message\n const userMsg: Message = {\n role: \"user\",\n content: rawInput,\n round: currentRound,\n };\n setMessages((prev) => [...prev, userMsg]);\n insertMessage({\n sessionId,\n role: \"user\",\n content: rawInput,\n round: currentRound,\n });\n\n const allMessages = [...messages, userMsg];\n const newMessages = await runAgents(allMessages, currentRound, target);\n\n // If aborted, the Escape handler already cleaned up\n if (newMessages.length === 0) return;\n\n setMessages((prev) => [...prev, ...newMessages]);\n setRoundNum(currentRound + 1);\n runningRoundRef.current = null;\n\n if (currentRound === 0 && !existingSessionId) {\n const title = prompt.length > 60 ? prompt.slice(0, 57) + \"...\" : prompt;\n updateSessionTitle(sessionId, title);\n }\n\n touchSession(sessionId);\n setState(\"input\");\n };\n\n const runDiscussion = async (prompt: string) => {\n setConsensusReached(false);\n let currentRound = roundNum;\n runningRoundRef.current = currentRound;\n\n // Add user message\n const userMsg: Message = {\n role: \"user\",\n content: `discuss ${prompt}`,\n round: currentRound,\n };\n setMessages((prev) => [...prev, userMsg]);\n insertMessage({\n sessionId,\n role: \"user\",\n content: `discuss ${prompt}`,\n round: currentRound,\n });\n\n let allMessages = [...messages, userMsg];\n\n if (currentRound === 0 && !existingSessionId) {\n const title = prompt.length > 60 ? prompt.slice(0, 57) + \"...\" : prompt;\n updateSessionTitle(sessionId, title);\n }\n\n for (let disc = 1; disc <= config.discussion.max_rounds; disc++) {\n setDiscussionRound(disc);\n\n const newMessages = await runAgents(\n allMessages,\n currentRound,\n \"both\",\n disc === 1 ? prompt : \"Provide your response for this round.\",\n true,\n );\n\n // If aborted, stop the discussion loop\n if (newMessages.length === 0) break;\n\n setMessages((prev) => [...prev, ...newMessages]);\n allMessages = [...allMessages, ...newMessages];\n currentRound++;\n\n // Check for consensus — both agents must include the marker\n const claudeMsg = newMessages.find((m) => m.role === \"claude\" && !m.error);\n const codexMsg = newMessages.find((m) => m.role === \"codex\" && !m.error);\n const claudeConsensus = claudeMsg?.content.includes(CONSENSUS_MARKER) ?? false;\n const codexConsensus = codexMsg?.content.includes(CONSENSUS_MARKER) ?? false;\n\n if (claudeConsensus && codexConsensus) {\n setConsensusReached(true);\n break;\n }\n }\n\n setRoundNum(currentRound);\n setDiscussionRound(0);\n runningRoundRef.current = null;\n touchSession(sessionId);\n setState(\"input\");\n };\n\n const handleSubmit = (value: string) => {\n setStatusMessage(null);\n\n if (value === \"/exit\") {\n closeDb();\n exit();\n return;\n }\n\n if (value === \"/help\") {\n setStatusMessage(\n [\n \"/help Show this help\",\n \"/config Edit configuration\",\n \"/new Start a new session\",\n \"/copy Copy conversation to clipboard\",\n \"/exit Exit the app\",\n \"\",\n \"Esc Interrupt running agents\",\n ].join(\"\\n\")\n );\n return;\n }\n\n if (value === \"/config\") {\n setState(\"config\");\n return;\n }\n\n if (value === \"/new\") {\n const newId = nanoid(12);\n createSession(newId, process.cwd());\n setSessionId(newId);\n setMessages([]);\n setRoundNum(0);\n setConsensusReached(false);\n setDiscussionRound(0);\n setStatusMessage(\"Started new session.\");\n return;\n }\n\n if (value === \"/copy\") {\n try {\n const md = formatAsMarkdown(messages);\n copyToClipboard(md);\n setStatusMessage(\"Copied conversation to clipboard.\");\n } catch {\n setStatusMessage(\"Failed to copy to clipboard.\");\n }\n return;\n }\n\n setConsensusReached(false);\n setState(\"running\");\n runRound(value);\n };\n\n return (\n <Box flexDirection=\"column\">\n <Header sessionId={sessionId} />\n\n {messages.map((msg, i) => {\n if (msg.role === \"user\") {\n return <UserMessage key={i} content={msg.content} />;\n }\n if (msg.role === \"claude\" || msg.role === \"codex\") {\n return (\n <AgentResponseBlock\n key={i}\n agent={msg.role}\n content={msg.content}\n error={msg.error}\n />\n );\n }\n return null;\n })}\n\n {discussionRound > 0 && thinkingAgents.length > 0 && (\n <DiscussionStatus round={discussionRound} maxRounds={config.discussion.max_rounds} />\n )}\n\n {thinkingAgents.length > 0 && (\n <Box flexDirection=\"column\" marginBottom={1}>\n {thinkingAgents.map((agent) => (\n <ThinkingIndicator key={agent} agent={agent} />\n ))}\n </Box>\n )}\n\n {consensusReached && <ConsensusReached />}\n\n {statusMessage && (\n <Box marginLeft={1}>\n <Text dimColor italic>{statusMessage}</Text>\n </Box>\n )}\n\n {state === \"config\" && (\n <InlineConfigEditor\n isActive={state === \"config\"}\n onClose={() => setState(\"input\")}\n />\n )}\n\n {state === \"input\" && <PromptInput onSubmit={handleSubmit} />}\n </Box>\n );\n}\n\n// --- Entry points ---\n\nexport function startApp(props: AppProps) {\n return render(<App {...props} />);\n}\n\nexport function showTranscriptMarkdown(sessionId: string): string {\n const dbMessages = getMessages(sessionId);\n const messages = dbMessages.map((m) => ({\n role: m.role as Message[\"role\"],\n content: m.content,\n round: m.round,\n }));\n return formatAsMarkdown(messages);\n}\n\nexport function showTranscript(sessionId: string): void {\n const dbMessages = getMessages(sessionId);\n const messages: Message[] = dbMessages.map((m) => ({\n role: m.role as Message[\"role\"],\n content: m.content,\n round: m.round,\n }));\n\n const { unmount } = render(\n <Box flexDirection=\"column\">\n <Header sessionId={sessionId} />\n {messages.map((msg, i) => {\n if (msg.role === \"user\") {\n return <UserMessage key={i} content={msg.content} />;\n }\n if (msg.role === \"claude\" || msg.role === \"codex\") {\n return (\n <AgentResponseBlock key={i} agent={msg.role} content={msg.content} />\n );\n }\n return null;\n })}\n <Box>\n <Text dimColor>{\"─\".repeat(60)}</Text>\n </Box>\n </Box>\n );\n\n unmount();\n}\n\nexport function showSessionList(\n sessions: Array<{\n id: string;\n title: string | null;\n status: string;\n created_at: string;\n updated_at: string;\n }>\n): void {\n const { unmount } = render(\n <Box flexDirection=\"column\">\n {sessions.length === 0 ? (\n <Text dimColor> No sessions found.</Text>\n ) : (\n sessions.map((s) => (\n <Box key={s.id} marginLeft={1}>\n <Text color=\"cyan\">{s.id.slice(0, 7)}</Text>\n <Text>{\" \"}</Text>\n <Text>{s.title || \"(untitled)\"}</Text>\n <Text>{\" \"}</Text>\n <Text color={s.status === \"active\" ? \"green\" : undefined} dimColor={s.status !== \"active\"}>\n {s.status}\n </Text>\n <Text>{\" \"}</Text>\n <Text dimColor>{s.updated_at}</Text>\n </Box>\n ))\n )}\n </Box>\n );\n\n unmount();\n}\n","import { spawn } from \"node:child_process\";\nimport { createInterface } from \"node:readline\";\nimport type { AgentEvent, AgentOptions, AgentResponse } from \"./types.js\";\n\n/**\n * Parse Claude Code's stream-json JSONL output into AgentEvents.\n *\n * Event format (one JSON object per line):\n * { type: \"system\", subtype: \"init\", ... }\n * { type: \"assistant\", message: { content: [{ type: \"text\", text }, { type: \"tool_use\", ... }] } }\n * { type: \"user\", message: { content: [{ type: \"tool_result\", ... }] } }\n * { type: \"result\", subtype: \"success\", result: \"final text\", ... }\n */\n\nasync function* streamClaude(\n options: AgentOptions\n): AsyncGenerator<AgentEvent> {\n const args = [\n \"-p\",\n \"--verbose\",\n \"--output-format\",\n \"stream-json\",\n \"--no-session-persistence\",\n ];\n\n if (options.systemPrompt) {\n args.push(\"--system-prompt\", options.systemPrompt);\n }\n if (options.model) {\n args.push(\"--model\", options.model);\n }\n\n args.push(options.prompt);\n\n const proc = spawn(\"claude\", args, {\n cwd: options.cwd,\n stdio: [\"ignore\", \"pipe\", \"inherit\"],\n env: { ...process.env, CLAUDECODE: \"\" },\n });\n\n // Handle spawn errors (e.g., command not found)\n let spawnErrorMsg = \"\";\n proc.on(\"error\", (err) => {\n spawnErrorMsg = err.message;\n });\n\n // Abort support — kill the child process when signalled\n if (options.signal) {\n if (options.signal.aborted) {\n proc.kill();\n } else {\n options.signal.addEventListener(\"abort\", () => proc.kill(), { once: true });\n }\n }\n\n const rl = createInterface({ input: proc.stdout! });\n let gotResultText = false;\n\n for await (const line of rl) {\n if (!line.trim()) continue;\n\n let data: any;\n try {\n data = JSON.parse(line);\n } catch {\n continue;\n }\n\n if (data.type === \"assistant\" && data.message?.content) {\n for (const block of data.message.content) {\n if (block.type === \"text\" && block.text) {\n yield { type: \"text\", agent: \"claude\", content: block.text };\n gotResultText = true;\n } else if (block.type === \"tool_use\") {\n yield {\n type: \"tool_call\",\n agent: \"claude\",\n toolName: block.name,\n toolInput:\n typeof block.input === \"string\"\n ? block.input\n : JSON.stringify(block.input),\n };\n }\n }\n } else if (data.type === \"user\" && data.message?.content) {\n for (const block of data.message.content) {\n if (block.type === \"tool_result\") {\n const text =\n typeof block.content === \"string\"\n ? block.content\n : Array.isArray(block.content)\n ? block.content\n .filter((c: any) => c.type === \"text\")\n .map((c: any) => c.text)\n .join(\"\\n\")\n : \"\";\n if (text) {\n yield {\n type: \"tool_result\",\n agent: \"claude\",\n toolOutput: text,\n };\n }\n }\n }\n } else if (data.type === \"result\") {\n if (data.is_error) {\n yield {\n type: \"error\",\n agent: \"claude\",\n content: data.error || data.result || \"Unknown error\",\n };\n } else if (data.result && !gotResultText) {\n // Use result.result as fallback if no assistant text blocks were emitted\n yield { type: \"text\", agent: \"claude\", content: data.result };\n }\n }\n }\n\n // Wait for the process to exit\n await new Promise<void>((resolve) => {\n proc.on(\"close\", resolve);\n });\n\n if (spawnErrorMsg) {\n yield {\n type: \"error\",\n agent: \"claude\",\n content: `Failed to spawn claude: ${spawnErrorMsg}`,\n };\n }\n\n yield { type: \"done\", agent: \"claude\" };\n}\n\nexport async function runClaude(options: AgentOptions): Promise<AgentResponse> {\n const start = Date.now();\n const events: AgentEvent[] = [];\n const textParts: string[] = [];\n const errors: string[] = [];\n\n for await (const event of streamClaude(options)) {\n events.push(event);\n if (event.type === \"text\" && event.content) {\n textParts.push(event.content);\n } else if (event.type === \"error\" && event.content) {\n errors.push(event.content);\n }\n }\n\n return {\n agent: \"claude\",\n text: textParts.join(\"\"),\n events,\n durationMs: Date.now() - start,\n error: errors.length > 0 ? errors.join(\"\\n\") : undefined,\n };\n}\n","import { spawn } from \"node:child_process\";\nimport { createInterface } from \"node:readline\";\nimport type { AgentEvent, AgentOptions, AgentResponse } from \"./types.js\";\n\n/**\n * Parse Codex CLI's exec --json JSONL output into AgentEvents.\n *\n * Event format (one JSON object per line):\n * { type: \"thread.started\", thread_id: \"...\" }\n * { type: \"turn.started\" }\n * { type: \"item.completed\", item: { type: \"agent_message\", text: \"...\" } }\n * { type: \"item.started\"|\"item.completed\", item: { type: \"command_execution\", command, aggregated_output, exit_code } }\n * { type: \"turn.completed\", usage: { ... } }\n */\n\nasync function* streamCodex(\n options: AgentOptions\n): AsyncGenerator<AgentEvent> {\n const args = [\"exec\", \"--json\", \"--full-auto\", \"--ephemeral\"];\n\n if (options.model) {\n args.push(\"-m\", options.model);\n }\n\n // Build the full prompt with system context prepended\n let fullPrompt = options.prompt;\n if (options.systemPrompt) {\n fullPrompt = `${options.systemPrompt}\\n\\n---\\n\\n${options.prompt}`;\n }\n\n args.push(fullPrompt);\n\n const proc = spawn(\"codex\", args, {\n cwd: options.cwd,\n stdio: [\"ignore\", \"pipe\", \"inherit\"],\n env: process.env,\n });\n\n // Handle spawn errors (e.g., command not found)\n let spawnErrorMsg = \"\";\n proc.on(\"error\", (err) => {\n spawnErrorMsg = err.message;\n });\n\n // Abort support — kill the child process when signalled\n if (options.signal) {\n if (options.signal.aborted) {\n proc.kill();\n } else {\n options.signal.addEventListener(\"abort\", () => proc.kill(), { once: true });\n }\n }\n\n const rl = createInterface({ input: proc.stdout! });\n\n for await (const line of rl) {\n if (!line.trim()) continue;\n\n let data: any;\n try {\n data = JSON.parse(line);\n } catch {\n continue;\n }\n\n if (data.type === \"item.completed\" && data.item) {\n const item = data.item;\n\n if (item.type === \"agent_message\" && item.text) {\n yield { type: \"text\", agent: \"codex\", content: item.text };\n } else if (item.type === \"command_execution\") {\n yield {\n type: \"tool_call\",\n agent: \"codex\",\n toolName: \"command\",\n toolInput: item.command,\n };\n if (item.aggregated_output) {\n yield {\n type: \"tool_result\",\n agent: \"codex\",\n toolOutput: item.aggregated_output,\n };\n }\n } else if (item.type === \"file_change\" && item.changes) {\n const desc = item.changes\n .map((c: any) => `${c.kind}: ${c.path}`)\n .join(\", \");\n yield {\n type: \"tool_result\",\n agent: \"codex\",\n toolName: \"file_change\",\n toolOutput: desc,\n };\n } else if (item.type === \"error\") {\n yield {\n type: \"error\",\n agent: \"codex\",\n content: item.message || \"Unknown error\",\n };\n }\n } else if (data.type === \"turn.failed\") {\n yield {\n type: \"error\",\n agent: \"codex\",\n content: data.error?.message || \"Turn failed\",\n };\n } else if (data.type === \"error\") {\n yield {\n type: \"error\",\n agent: \"codex\",\n content: data.message || \"Stream error\",\n };\n }\n }\n\n // Wait for the process to exit\n await new Promise<void>((resolve) => {\n proc.on(\"close\", resolve);\n });\n\n if (spawnErrorMsg) {\n yield {\n type: \"error\",\n agent: \"codex\",\n content: `Failed to spawn codex: ${spawnErrorMsg}`,\n };\n }\n\n yield { type: \"done\", agent: \"codex\" };\n}\n\nexport async function runCodex(options: AgentOptions): Promise<AgentResponse> {\n const start = Date.now();\n const events: AgentEvent[] = [];\n const textParts: string[] = [];\n const errors: string[] = [];\n\n for await (const event of streamCodex(options)) {\n events.push(event);\n if (event.type === \"text\" && event.content) {\n textParts.push(event.content);\n } else if (event.type === \"error\" && event.content) {\n errors.push(event.content);\n }\n }\n\n return {\n agent: \"codex\",\n text: textParts.join(\"\"),\n events,\n durationMs: Date.now() - start,\n error: errors.length > 0 ? errors.join(\"\\n\") : undefined,\n };\n}\n","interface Message {\n role: \"user\" | \"claude\" | \"codex\" | \"system\";\n content: string;\n error?: boolean;\n}\n\nexport function formatAsMarkdown(messages: Message[]): string {\n const parts: string[] = [];\n\n for (const msg of messages) {\n if (msg.role === \"system\") continue;\n\n if (msg.role === \"user\") {\n parts.push(`**You:** ${msg.content}`);\n } else {\n const name = msg.role === \"claude\" ? \"Claude\" : \"Codex\";\n if (msg.error) {\n parts.push(`**${name}:** *(error)*\\n\\n${msg.content}`);\n } else {\n parts.push(`**${name}:**\\n\\n${msg.content}`);\n }\n }\n }\n\n return parts.join(\"\\n\\n---\\n\\n\") + \"\\n\";\n}\n","import { execSync } from \"node:child_process\";\n\nexport function copyToClipboard(text: string): void {\n const platform = process.platform;\n\n let cmd: string;\n if (platform === \"darwin\") {\n cmd = \"pbcopy\";\n } else if (platform === \"win32\") {\n cmd = \"clip\";\n } else {\n // Linux — try xclip first, fall back to xsel\n try {\n execSync(\"which xclip\", { stdio: \"ignore\" });\n cmd = \"xclip -selection clipboard\";\n } catch {\n cmd = \"xsel --clipboard --input\";\n }\n }\n\n execSync(cmd, { input: text, stdio: [\"pipe\", \"ignore\", \"ignore\"] });\n}\n","import Database from \"better-sqlite3\";\nimport { join } from \"node:path\";\nimport { getConfigDir, ensureConfigDir } from \"../config.js\";\n\nlet db: Database.Database | null = null;\n\nexport function getDbPath(): string {\n return join(getConfigDir(), \"tagteam.db\");\n}\n\nexport function getDb(): Database.Database {\n if (db) return db;\n\n ensureConfigDir();\n db = new Database(getDbPath());\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"foreign_keys = ON\");\n\n initSchema(db);\n return db;\n}\n\nfunction initSchema(db: Database.Database): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n title TEXT,\n working_dir TEXT NOT NULL,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n updated_at TEXT NOT NULL DEFAULT (datetime('now')),\n status TEXT NOT NULL DEFAULT 'active'\n );\n\n CREATE TABLE IF NOT EXISTS messages (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n session_id TEXT NOT NULL REFERENCES sessions(id),\n role TEXT NOT NULL,\n content TEXT NOT NULL,\n round INTEGER NOT NULL DEFAULT 0,\n duration_ms INTEGER,\n metadata TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id, id);\n `);\n}\n\nexport function closeDb(): void {\n if (db) {\n db.close();\n db = null;\n }\n}\n","import { getDb } from \"./index.js\";\n\nexport interface Session {\n id: string;\n title: string | null;\n working_dir: string;\n created_at: string;\n updated_at: string;\n status: string;\n}\n\nexport function createSession(\n id: string,\n workingDir: string\n): Session {\n const db = getDb();\n db.prepare(\n `INSERT INTO sessions (id, working_dir) VALUES (?, ?)`\n ).run(id, workingDir);\n\n return getSession(id)!;\n}\n\nexport function getSession(id: string): Session | undefined {\n const db = getDb();\n return db.prepare(`SELECT * FROM sessions WHERE id = ?`).get(id) as\n | Session\n | undefined;\n}\n\nexport function getSessionByPrefix(prefix: string): Session | undefined {\n const db = getDb();\n return db\n .prepare(`SELECT * FROM sessions WHERE id LIKE ? ORDER BY updated_at DESC LIMIT 1`)\n .get(`${prefix}%`) as Session | undefined;\n}\n\nexport function getMostRecentSession(): Session | undefined {\n const db = getDb();\n return db\n .prepare(\n `SELECT * FROM sessions WHERE status = 'active' ORDER BY updated_at DESC LIMIT 1`\n )\n .get() as Session | undefined;\n}\n\nexport function listSessions(limit = 20): Session[] {\n const db = getDb();\n return db\n .prepare(`SELECT * FROM sessions ORDER BY updated_at DESC LIMIT ?`)\n .all(limit) as Session[];\n}\n\nexport function updateSessionTitle(id: string, title: string): void {\n const db = getDb();\n db.prepare(\n `UPDATE sessions SET title = ?, updated_at = datetime('now') WHERE id = ?`\n ).run(title, id);\n}\n\nexport function touchSession(id: string): void {\n const db = getDb();\n db.prepare(`UPDATE sessions SET updated_at = datetime('now') WHERE id = ?`).run(\n id\n );\n}\n","import { getDb } from \"./index.js\";\n\nexport interface Message {\n id: number;\n session_id: string;\n role: string;\n content: string;\n round: number;\n duration_ms: number | null;\n metadata: string | null;\n created_at: string;\n}\n\nexport function insertMessage(params: {\n sessionId: string;\n role: string;\n content: string;\n round: number;\n durationMs?: number;\n metadata?: Record<string, unknown>;\n}): Message {\n const db = getDb();\n const result = db\n .prepare(\n `INSERT INTO messages (session_id, role, content, round, duration_ms, metadata)\n VALUES (?, ?, ?, ?, ?, ?)`\n )\n .run(\n params.sessionId,\n params.role,\n params.content,\n params.round,\n params.durationMs ?? null,\n params.metadata ? JSON.stringify(params.metadata) : null\n );\n\n return db\n .prepare(`SELECT * FROM messages WHERE id = ?`)\n .get(result.lastInsertRowid) as Message;\n}\n\nexport function getMessages(sessionId: string): Message[] {\n const db = getDb();\n return db\n .prepare(`SELECT * FROM messages WHERE session_id = ? ORDER BY id`)\n .all(sessionId) as Message[];\n}\n\nexport function deleteMessagesFromRound(\n sessionId: string,\n fromRound: number\n): void {\n const db = getDb();\n db.prepare(\n `DELETE FROM messages WHERE session_id = ? AND round >= ?`\n ).run(sessionId, fromRound);\n}","import type { AgentName } from \"./agents/types.js\";\n\nconst OTHER: Record<AgentName, string> = {\n claude: \"Codex (OpenAI)\",\n codex: \"Claude (Anthropic)\",\n};\n\nexport function collaborationPrompt(agent: AgentName): string {\n return `You are in a collaborative session with ${OTHER[agent]}. You'll both respond to the user's prompt independently, then see each other's responses. In discussion rounds: highlight where you agree, constructively address disagreements, and build on each other's ideas. Be concise - avoid repeating what was already said.`;\n}\n\nexport function discussionPrompt(\n agent: AgentName,\n conversationHistory: string\n): string {\n return `${collaborationPrompt(agent)}\n\nHere is the conversation so far:\n\n${conversationHistory}\n\nNow provide your response for this discussion round. Build on what was said, highlight agreements, and address any disagreements constructively. Be concise.`;\n}\n\nexport function debatePrompt(agent: AgentName): string {\n return `You are in a structured debate with ${OTHER[agent]}. You'll both respond to the user's prompt, then see each other's responses and discuss.\n\nYour goal is to reach consensus through constructive discussion. In each round:\n- Address specific points of agreement and disagreement\n- Refine your position based on valid arguments from ${OTHER[agent]}\n- Be concise — don't repeat points already established\n\nWhen you believe you and ${OTHER[agent]} have reached substantial agreement on the key points, end your response with [CONSENSUS] on its own line. Only do this when you genuinely agree — don't force premature consensus.`;\n}\n\nexport function debateRoundPrompt(\n agent: AgentName,\n conversationHistory: string\n): string {\n return `${debatePrompt(agent)}\n\nHere is the conversation so far:\n\n${conversationHistory}\n\nRespond to the latest round. If you agree with ${OTHER[agent]}'s position on all key points, end with [CONSENSUS]. Otherwise, continue the discussion.`;\n}\n\nexport const CONSENSUS_MARKER = \"[CONSENSUS]\";\n\nexport function formatConversationHistory(\n messages: Array<{ role: string; agent?: AgentName; content: string }>\n): string {\n return messages\n .map((m) => {\n const label =\n m.role === \"user\"\n ? \"User\"\n : m.agent === \"claude\"\n ? \"Claude\"\n : \"Codex\";\n return `[${label}]: ${m.content}`;\n })\n .join(\"\\n\\n\");\n}\n","import React, { useState } from \"react\";\nimport { render, Box, Text, useApp, useInput } from \"ink\";\nimport TextInput from \"ink-text-input\";\nimport { loadConfig, setConfigValue } from \"./config.js\";\nimport type { TagTeamConfig } from \"./config.js\";\n\ninterface ConfigField {\n key: string;\n label: string;\n get: (c: TagTeamConfig) => string;\n type: \"string\" | \"number\";\n}\n\nconst CONFIG_FIELDS: ConfigField[] = [\n {\n key: \"claude.model\",\n label: \"Claude model\",\n get: (c) => c.claude.model,\n type: \"string\",\n },\n {\n key: \"codex.model\",\n label: \"Codex model\",\n get: (c) => c.codex.model,\n type: \"string\",\n },\n {\n key: \"discussion.max_rounds\",\n label: \"Discussion max rounds\",\n get: (c) => String(c.discussion.max_rounds),\n type: \"number\",\n },\n];\n\nconst LABEL_WIDTH = Math.max(...CONFIG_FIELDS.map((f) => f.label.length));\n\ntype EditMode = \"select\" | \"edit\";\n\ninterface InlineConfigEditorProps {\n isActive: boolean;\n onClose: () => void;\n}\n\nexport function InlineConfigEditor({ isActive, onClose }: InlineConfigEditorProps) {\n const [config, setConfig] = useState(() => loadConfig());\n const [selectedIndex, setSelectedIndex] = useState(0);\n const [mode, setMode] = useState<EditMode>(\"select\");\n const [editValue, setEditValue] = useState(\"\");\n const [savedMessage, setSavedMessage] = useState<string | null>(null);\n\n useInput(\n (input, key) => {\n if (key.upArrow) {\n setSavedMessage(null);\n setSelectedIndex((i) => (i > 0 ? i - 1 : CONFIG_FIELDS.length - 1));\n } else if (key.downArrow) {\n setSavedMessage(null);\n setSelectedIndex((i) => (i < CONFIG_FIELDS.length - 1 ? i + 1 : 0));\n } else if (key.return) {\n const field = CONFIG_FIELDS[selectedIndex];\n setEditValue(field.get(config));\n setSavedMessage(null);\n setMode(\"edit\");\n } else if (key.escape || input === \"q\") {\n onClose();\n }\n },\n { isActive: isActive && mode === \"select\" }\n );\n\n useInput(\n (_input, key) => {\n if (key.escape) {\n setMode(\"select\");\n }\n },\n { isActive: isActive && mode === \"edit\" }\n );\n\n const handleEditSubmit = (value: string) => {\n const field = CONFIG_FIELDS[selectedIndex];\n\n if (field.type === \"number\") {\n const n = Number(value);\n if (!Number.isInteger(n) || n < 1) {\n setSavedMessage(\"Error: must be a positive integer\");\n setMode(\"select\");\n return;\n }\n }\n\n try {\n const updated = setConfigValue(field.key, value);\n setConfig(updated);\n setSavedMessage(`Saved ${field.key} = ${value}`);\n } catch (e: any) {\n setSavedMessage(`Error: ${e.message}`);\n }\n\n setMode(\"select\");\n };\n\n return (\n <Box flexDirection=\"column\">\n <Box marginBottom={1}>\n <Text bold>Configuration</Text>\n <Text dimColor> ── edit values inline</Text>\n </Box>\n\n {CONFIG_FIELDS.map((field, i) => {\n const selected = i === selectedIndex;\n const pointer = selected ? \"> \" : \" \";\n const currentValue = field.get(config);\n\n return (\n <Box key={field.key} marginLeft={1}>\n <Text color={selected ? \"cyan\" : undefined} bold={selected}>\n {pointer}\n {field.label.padEnd(LABEL_WIDTH)}\n </Text>\n <Text dimColor> = </Text>\n {mode === \"edit\" && selected ? (\n <TextInput\n value={editValue}\n onChange={setEditValue}\n onSubmit={handleEditSubmit}\n showCursor\n />\n ) : (\n <Text color=\"white\">{currentValue}</Text>\n )}\n </Box>\n );\n })}\n\n {savedMessage && (\n <Box marginTop={1} marginLeft={1}>\n <Text color={savedMessage.startsWith(\"Error\") ? \"red\" : \"green\"}>\n {savedMessage}\n </Text>\n </Box>\n )}\n\n <Box marginTop={1} marginLeft={1}>\n <Text dimColor>\n {mode === \"edit\"\n ? \"Enter save Esc cancel\"\n : \"↑↓ navigate Enter edit Esc/q quit\"}\n </Text>\n </Box>\n </Box>\n );\n}\n\n// Standalone entrypoint for `tagteam config edit`\nfunction StandaloneConfigEditor() {\n const { exit } = useApp();\n return <InlineConfigEditor isActive={true} onClose={exit} />;\n}\n\nexport function startConfigEditor() {\n return render(<StandaloneConfigEditor />);\n}\n"],"mappings":"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","names":["useState","render","Box","Text","useApp","useInput","TextInput","spawn","createInterface","join","join","db","db","db","jsx","jsxs","Text","Box","useState","TextInput","showTranscript","useApp","useInput","render","session","dbMessages","transcript","instance"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tagteam",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Orchestrate Claude and Codex in collaborative AI sessions",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"tagteam": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsup",
|
|
14
|
+
"dev": "tsx src/index.ts",
|
|
15
|
+
"start": "node dist/index.js",
|
|
16
|
+
"prepublishOnly": "npm run build"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"ai",
|
|
20
|
+
"claude",
|
|
21
|
+
"codex",
|
|
22
|
+
"agents",
|
|
23
|
+
"orchestration"
|
|
24
|
+
],
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=22"
|
|
27
|
+
},
|
|
28
|
+
"author": "Christopher Saylor",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/cwsaylor/tagteam.git"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"better-sqlite3": "^11.8.1",
|
|
36
|
+
"chalk": "^5.4.1",
|
|
37
|
+
"commander": "^13.1.0",
|
|
38
|
+
"ink": "^6.8.0",
|
|
39
|
+
"ink-spinner": "^5.0.0",
|
|
40
|
+
"ink-text-input": "^6.0.0",
|
|
41
|
+
"marked": "^15.0.7",
|
|
42
|
+
"marked-terminal": "^7.3.0",
|
|
43
|
+
"nanoid": "^5.1.2",
|
|
44
|
+
"react": "^19.2.4",
|
|
45
|
+
"smol-toml": "^1.3.1"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/better-sqlite3": "^7.6.12",
|
|
49
|
+
"@types/node": "^22.13.4",
|
|
50
|
+
"@types/react": "^19.2.14",
|
|
51
|
+
"tsup": "^8.4.0",
|
|
52
|
+
"tsx": "^4.19.3",
|
|
53
|
+
"typescript": "^5.7.3"
|
|
54
|
+
}
|
|
55
|
+
}
|