diff --git a/.gitignore b/.gitignore index 98e604d3..56098f88 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ packages/*/dist-firefox/ # Editor files .vscode/ +.zed/ .idea/ *.swp *.swo @@ -23,4 +24,4 @@ packages/*/dist-firefox/ coverage/ .nyc_output/ .pi_config/ -tui-debug.log \ No newline at end of file +tui-debug.log diff --git a/packages/coding-agent/src/main.ts b/packages/coding-agent/src/main.ts index e6e7431f..12c80360 100644 --- a/packages/coding-agent/src/main.ts +++ b/packages/coding-agent/src/main.ts @@ -45,6 +45,7 @@ interface Args { model?: string; apiKey?: string; systemPrompt?: string; + appendSystemPrompt?: string; thinking?: ThinkingLevel; continue?: boolean; resume?: boolean; @@ -88,6 +89,8 @@ function parseArgs(args: string[]): Args { result.apiKey = args[++i]; } else if (arg === "--system-prompt" && i + 1 < args.length) { result.systemPrompt = args[++i]; + } else if (arg === "--append-system-prompt" && i + 1 < args.length) { + result.appendSystemPrompt = args[++i]; } else if (arg === "--no-session") { result.noSession = true; } else if (arg === "--session" && i + 1 < args.length) { @@ -231,22 +234,23 @@ ${chalk.bold("Usage:")} ${APP_NAME} [options] [@files...] [messages...] ${chalk.bold("Options:")} - --provider Provider name (default: google) - --model Model ID (default: gemini-2.5-flash) - --api-key API key (defaults to env vars) - --system-prompt System prompt (default: coding assistant prompt) - --mode Output mode: text (default), json, or rpc - --print, -p Non-interactive mode: process prompt and exit - --continue, -c Continue previous session - --resume, -r Select a session to resume - --session Use specific session file - --no-session Don't save session (ephemeral) - --models Comma-separated model patterns for quick cycling with Ctrl+P - --tools Comma-separated list of tools to enable (default: read,bash,edit,write) - Available: read, bash, edit, write, grep, find, ls - --thinking Set thinking level: off, minimal, low, medium, high - --export Export session file to HTML and exit - --help, -h Show this help + --provider Provider name (default: google) + --model Model ID (default: gemini-2.5-flash) + --api-key API key (defaults to env vars) + --system-prompt System prompt (default: coding assistant prompt) + --append-system-prompt Append text or file contents to the system prompt + --mode Output mode: text (default), json, or rpc + --print, -p Non-interactive mode: process prompt and exit + --continue, -c Continue previous session + --resume, -r Select a session to resume + --session Use specific session file + --no-session Don't save session (ephemeral) + --models Comma-separated model patterns for quick cycling with Ctrl+P + --tools Comma-separated list of tools to enable (default: read,bash,edit,write) + Available: read, bash, edit, write, grep, find, ls + --thinking Set thinking level: off, minimal, low, medium, high + --export Export session file to HTML and exit + --help, -h Show this help ${chalk.bold("Examples:")} # Interactive mode @@ -320,32 +324,47 @@ const toolDescriptions: Record = { ls: "List directory contents", }; -function buildSystemPrompt(customPrompt?: string, selectedTools?: ToolName[]): string { - // Check if customPrompt is a file path that exists - if (customPrompt && existsSync(customPrompt)) { +function resolvePromptInput(input: string | undefined, description: string): string | undefined { + if (!input) { + return undefined; + } + + if (existsSync(input)) { try { - customPrompt = readFileSync(customPrompt, "utf-8"); + return readFileSync(input, "utf-8"); } catch (error) { - console.error(chalk.yellow(`Warning: Could not read system prompt file ${customPrompt}: ${error}`)); - // Fall through to use as literal string + console.error(chalk.yellow(`Warning: Could not read ${description} file ${input}: ${error}`)); + return input; } } - if (customPrompt) { - // Use custom prompt as base, then add context/datetime - const now = new Date(); - const dateTime = now.toLocaleString("en-US", { - weekday: "long", - year: "numeric", - month: "long", - day: "numeric", - hour: "2-digit", - minute: "2-digit", - second: "2-digit", - timeZoneName: "short", - }); + return input; +} - let prompt = customPrompt; +function buildSystemPrompt(customPrompt?: string, selectedTools?: ToolName[], appendSystemPrompt?: string): string { + const resolvedCustomPrompt = resolvePromptInput(customPrompt, "system prompt"); + const resolvedAppendPrompt = resolvePromptInput(appendSystemPrompt, "append system prompt"); + + const now = new Date(); + const dateTime = now.toLocaleString("en-US", { + weekday: "long", + year: "numeric", + month: "long", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + timeZoneName: "short", + }); + + const appendSection = resolvedAppendPrompt ? `\n\n${resolvedAppendPrompt}` : ""; + + if (resolvedCustomPrompt) { + let prompt = resolvedCustomPrompt; + + if (appendSection) { + prompt += appendSection; + } // Append project context files const contextFiles = loadProjectContextFiles(); @@ -364,18 +383,6 @@ function buildSystemPrompt(customPrompt?: string, selectedTools?: ToolName[]): s return prompt; } - const now = new Date(); - const dateTime = now.toLocaleString("en-US", { - weekday: "long", - year: "numeric", - month: "long", - day: "numeric", - hour: "2-digit", - minute: "2-digit", - second: "2-digit", - timeZoneName: "short", - }); - // Get absolute path to README.md const readmePath = getReadmePath(); @@ -453,6 +460,10 @@ Documentation: - Your own documentation (including custom model setup and theme creation) is at: ${readmePath} - Read it when users ask about features, configuration, or setup, and especially if the user asks you to add a custom model or provider, or create a custom theme.`; + if (appendSection) { + prompt += appendSection; + } + // Append project context files const contextFiles = loadProjectContextFiles(); if (contextFiles.length > 0) { @@ -1138,7 +1149,7 @@ export async function main(args: string[]) { } } - const systemPrompt = buildSystemPrompt(parsed.systemPrompt, parsed.tools); + const systemPrompt = buildSystemPrompt(parsed.systemPrompt, parsed.tools, parsed.appendSystemPrompt); // Load previous messages if continuing or resuming // This may update initialModel if restoring from session