feat(cli): Add /export command to export chat history to markdown and jsonl - #5342
feat(cli): Add /export command to export chat history to markdown and jsonl#5342ssarangi wants to merge 5 commits into
Conversation
This commit introduces a new slash command, `/export`, allowing users to export their current chat session to a file. This addresses the functionality requested in google-gemini#4191, google-gemini#3882, and google-gemini#5101. The command supports two formats: - `/export jsonl`: Exports the conversation in JSONL format. - `/export markdown`: Exports the conversation in Markdown format. An optional `--output <file_path>` flag can be used to specify an output file. If the flag is omitted, the content is printed directly to the console. The implementation includes a comprehensive test suite covering functionality, edge cases, and error handling.
There was a problem hiding this comment.
Summary of Changes
Hello @ssarangi, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request primarily introduces a new /export command to the CLI, fulfilling user requests to save chat history. This command allows exporting conversations in either JSONL or Markdown format, with options to output to the console or a file. Additionally, the PR includes the creation of a new mock server, mcp-server, which appears to be a separate, albeit potentially related, development effort for handling tool execution requests.
Highlights
- New
/exportCLI Command: Introduces a new/exportcommand to the CLI, enabling users to export their chat history. - Multiple Export Formats: The
/exportcommand supports two subcommands,/export jsonland/export markdown, allowing users to export chat history in JSON Lines (jsonl) or Markdown format. - Flexible Output Options: Users can choose to print the exported conversation directly to the console or save it to a specified file using the
--output <file_path>flag. - Robust Error Handling and Edge Cases: The implementation includes comprehensive checks for scenarios such as no active chat client, empty conversation history, and file write failures, providing informative messages to the user.
- New Mock Server for MCP: A new
mcp-serverdirectory has been added, containing a basic Node.js Express server that acts as a mock for a 'Custom MCP Server,' handling/tool/executerequests. This appears to be a separate addition not directly related to the chat export functionality described in the PR title and body.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments or fill out our survey to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
There was a problem hiding this comment.
Code Review
This pull request introduces a valuable /export command for saving chat history. The implementation is well-structured with good test coverage. My review focuses on improving robustness, security, and data integrity. Key suggestions include updating outdated and vulnerable dependencies in the new mock server, fixing a critical data loss bug in the export logic where non-text message parts are ignored, and making the command-line argument parsing more robust to handle file paths with spaces.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a useful /export command for saving chat history. The implementation is solid, with good test coverage. However, I've identified a few critical and high-severity issues that should be addressed. The new mock server's package.json has a configuration issue that will prevent it from starting and uses outdated dependencies with known vulnerabilities. Additionally, the export functionality has a data loss bug for non-text message parts, and the command's argument parsing is not robust enough to handle file paths with spaces.
| "name": "mcp-server", | ||
| "version": "1.0.0", | ||
| "description": "A custom MCP server", | ||
| "main": "index.js", |
There was a problem hiding this comment.
The mcp-server/index.js file uses ES module syntax (import). However, this package.json file is missing the "type": "module" field. Without it, Node.js will treat .js files as CommonJS modules by default, which will cause a syntax error when it encounters the import statement. This will prevent the server from starting.
"main": "index.js",
"type": "module",
| "dependencies": { | ||
| "express": "^4.17.1" | ||
| }, | ||
| "devDependencies": { | ||
| "nodemon": "^2.0.15" | ||
| } |
There was a problem hiding this comment.
The versions for express (^4.17.1) and nodemon (^2.0.15) are outdated. Older versions of express in the 4.x line have known security vulnerabilities (e.g., CVE-2022-24999). It's important to use updated packages to ensure security and stability. Please update these dependencies to their latest stable versions.
"dependencies": {
"express": "^4.19.2"
},
"devDependencies": {
"nodemon": "^3.1.0"
}
| text: | ||
| item.parts | ||
| ?.map((part: { text?: string }) => | ||
| 'text' in part ? part.text : '', | ||
| ) | ||
| .join('') || '', |
There was a problem hiding this comment.
The current implementation only handles text parts of a message, which can lead to data loss during export if the conversation contains other content like images (inlineData). To prevent this, you should handle other Part types to avoid exporting incomplete conversations. A similar change should be applied to the model role handling below.
text:
item.parts
?.map((part) => {
if ('text' in part && part.text) return part.text;
if ('inlineData' in part) return '[Image content not supported in export]';
return '';
})
.join('') || '',| const argParts = args.split(' ').filter(Boolean); // Split by space and remove empty strings | ||
| const outputIndex = argParts.indexOf(outputFlag); | ||
| let outputPath: string | undefined; | ||
|
|
||
| if (outputIndex !== -1 && outputIndex + 1 < argParts.length) { | ||
| outputPath = argParts[outputIndex + 1]; | ||
| } |
There was a problem hiding this comment.
The argument parsing for the --output flag using args.split(' ') is not robust. It will fail for file paths that contain spaces, even if they are quoted. This can lead to unexpected behavior and a poor user experience. Please use a more reliable method for parsing arguments, such as a dedicated library or a more robust regex.
| const argParts = args.split(' ').filter(Boolean); // Split by space and remove empty strings | |
| const outputIndex = argParts.indexOf(outputFlag); | |
| let outputPath: string | undefined; | |
| if (outputIndex !== -1 && outputIndex + 1 < argParts.length) { | |
| outputPath = argParts[outputIndex + 1]; | |
| } | |
| // Using a regex to handle quoted paths. For more complex scenarios, a dedicated arg parser is recommended. | |
| const outputMatch = args.match(/--output\s+((?:\"[^\"]+\"|'[^']+'|\S+))/); | |
| const outputPath = outputMatch ? outputMatch[1].replace(/['"]/g, '') : undefined; | |
|
My take on the very idea of such manual exports: #3882 (comment) |
This commit introduces a new slash command, `/export`, allowing users to export their current chat session to a file. This addresses the functionality requested in google-gemini#4191, google-gemini#3882, and google-gemini#5101. The command supports two formats: - `/export jsonl`: Exports the conversation in JSONL format. - `/export markdown`: Exports the conversation in Markdown format. An optional `--output <file_path>` flag can be used to specify an output file. If the flag is omitted, the content is printed directly to the console. The implementation includes a comprehensive test suite covering functionality, edge cases, and error handling.
|
Here's a sed expression to extract prompts from gemini-cli text output: cat ./gemini-cli-promptlog.01.txt | \
grep -E '│ > (.*)' -A 2 | grep '^│' | sed 's/^\s*│\s*/ /g' | sed 's/^\s*>/-/' | sed 's/\s*│$//'
|
|
That's a clever With this pull request, you'll be able to use the new For example, to export to markdown:
And similarly for JSONL:
The "Reviewer Test Plan" in the pull request description provides more detailed examples of how to use this new functionality. |
|
e.g. simonw/llm optionally logs all prompts and outputs to SQLite; so that you don't have to hope that you typed
jsonl or sqlite or duckdb in WASM:
|
|
is there any updates on this pr? |
|
Would .ipynb format solve for this?
Unfortunately there's not yet a markdown format that includes output cells
(likely due to the unusability of base64 encoded binary data). There are
existing issues TODO to create a new format for Jupyter notebooks; which
have notebook-level metadata, cell-level metadata, input cells, and output
cells
…On Sun, Aug 31, 2025, 11:40 AM BitBeaver ***@***.***> wrote:
*BitBeaver-182* left a comment (google-gemini/gemini-cli#5342)
<#5342 (comment)>
is there any updates on this pr?
—
Reply to this email directly, view it on GitHub
<#5342 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAMNS6N26PSLJLTVOR5PSD3QMJQRAVCNFSM6AAAAACC34GGV6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTENBQGIZDSOBRHA>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
|
Thank you for the contribution! We're closing this as there haven't been updates in 60 days. If you'd like to re-open, please ensure there is issue attached that has been approved by and discussed with a maintainer and merge conflicts and comments resolved. |
TLDR
This pull request introduces a new
/exportcommand that allows users to export their chat history to eitherjsonlormarkdownformat. This functionality addresses several open issues requesting a way to save conversations.Dive Deeper
The
/exportcommand is implemented with two sub-commands:/export jsonland/export markdown. It includes an--output <file_path>flag to save the conversation to a file. If the flag is omitted, the output is printed directly to the console for maximum flexibility.During development, the
CommandServicewas significantly refactored on themainbranch. This PR adapts the new command to the updated architecture by registering it in theBuiltinCommandLoader. The implementation also includes a robust test suite covering happy paths, edge cases (like empty history), and error handling (like file write failures).Reviewer Test Plan
To validate this change, please pull down the branch and run the following commands in the Gemini CLI:
/export markdown. Verify that the conversation is printed to the terminal in Markdown format./export markdown --output test.md. Verify that atest.mdfile is created with the correct content./export jsonl. Verify that the conversation is printed in JSONL format./export jsonl --output test.jsonl. Verify that atest.jsonlfile is created./help export. Verify that the description clearly explains the--outputflag./clearand then/export markdown. Verify you get an informational message stating there is no conversation to export.Testing Matrix
Linked issues / bugs
Closes #4191
Closes #3882
Closes #5101