ai-cli-log 1.0.1 → 1.0.2

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/GEMINI.md ADDED
@@ -0,0 +1,53 @@
1
+ # GEMINI.md - ai-cli-log 项目开发指南
2
+
3
+ 本文档概述了 `ai-cli-log` 项目在开发过程中确立的关键架构决策、编码标准和开发偏好,这些主要通过与 Google Gemini 的互动形成。它将作为未来开发和维护的指南。
4
+
5
+ ## 1. 项目概览
6
+
7
+ * **项目名称:** `ai-cli-log`
8
+ * **项目目的:** 一个命令行界面 (CLI) 工具,旨在无缝捕获与 AI 模型(如 Gemini、Claude)的交互式终端会话,并将包括用户输入和渲染输出在内的整个交互过程保存为清晰的 Markdown 文档。
9
+ * **核心技术栈:** Node.js (TypeScript)。
10
+
11
+ ## 2. 架构原则与核心库
12
+
13
+ * **交互式会话捕获:**
14
+ * **伪终端 (PTY) 模拟:** 使用 `node-pty` 来启动子进程(即被包装的 CLI 工具),并提供一个完全交互式的终端环境,确保正确处理提示符、行缓冲和控制字符。
15
+ * **终端渲染与 ANSI 解析:** 采用 `@xterm/headless` 来解释 ANSI 转义码并维护一个虚拟屏幕缓冲区。这使得能够捕获“渲染后”的输出,反映终端屏幕在退格、光标移动和清屏等操作后的最终状态。
16
+ * **输入/输出处理:**
17
+ * `process.stdin` 被管道连接到 `node-pty` 实例 (`term.write()`),以便将用户输入传递给被包装的命令。
18
+ * `node-pty` 的 `onData` 事件将子进程的输出同时管道连接到 `process.stdout`(用于实时显示)和 `xterm` 实例(用于渲染和捕获)。
19
+ * **异步操作:** 所有文件系统操作 (`fs.writeFile`) 均以异步方式处理。`process.exit` 被明确地放置在 `fs.writeFile` 的回调函数内部,以确保应用程序在日志文件完全写入之前不会终止。
20
+ * **错误处理:** 关键错误(例如,子进程启动失败、文件写入错误)会被记录到 `console.error`。
21
+
22
+ ## 3. 编码标准与约定
23
+
24
+ * **语言:** TypeScript 是主要的开发语言,利用其类型安全和现代特性。
25
+ * **文件结构:**
26
+ * `src/index.ts`: 包含主应用程序逻辑。
27
+ * `dist/`: 编译后的 JavaScript 输出目录。
28
+ * `.ai-cli-logs/`: 用于存储生成的会话日志 Markdown 文件的目录。如果该目录不存在,则会自动创建。
29
+ * `bin/`: 包含 CLI 工具的启动脚本。
30
+ * **日志格式:**
31
+ * **内容:** 日志文件捕获来自 `xterm/headless` 缓冲区的“渲染后”终端输出,真实地呈现用户所看到的内容。这包括所有交互元素、输入和输出。
32
+ * **格式:** Markdown (`.md`) 文件,便于阅读和文档化。
33
+ * **文件名约定:** `[command_prefix]-YYYYMMDD-HHMMSS.md`。`command_prefix` 来自于被包装的命令(例如 `gemini`、`claude`),如果未提供命令,则默认为 `session`。时间戳使用 `YYYYMMDD-HHMMSS` 格式(不含冒号),以提高 URL 友好性。
34
+ * **Xterm.js 配置:**
35
+ * `scrollback: Infinity`: 确保捕获整个回滚缓冲区,而不仅仅是可见屏幕。
36
+ * `allowProposedApi: true`: 明确启用 `@xterm/headless` 中的实验性 API。
37
+ * **Polyfills:** 避免使用浏览器特定的 polyfills(如 `global.self` 或 `global.document` 模拟),如果存在 Node.js 原生或无头版本的库(例如,优先选择 `@xterm/headless` 而非 `xterm`)。
38
+
39
+ ## 4. 开发工作流
40
+
41
+ * **构建:** `npm run build` (执行 `tsc` 进行 TypeScript 编译)。
42
+ * **运行:** `npm run start` 或通过全局链接的 `ai-cli-log <command> [args...]` 直接运行。
43
+ * **调试:** 调试时可以使用临时的 `console.log` 语句,但在提交前应将其移除。
44
+ * **依赖管理:** 通过 `package.json` 和 `npm` 进行管理。
45
+ * **CLI 入口点规范:** 采用独立的 `bin/ai-cli-log.js` 脚本作为 CLI 入口点,该脚本包含 shebang (`#!/usr/bin/env node`) 并 `require` 编译后的主文件 (`dist/index.js`)。这是一种更健壮和标准化的方法,符合 Node.js CLI 的常见实践。
46
+
47
+ ## 5. 一般偏好
48
+
49
+ * **命名约定:** 偏好清晰、简洁和现代的名称,能准确反映工具的用途(例如,`ai-cli-log` 因其在 AI、CLI 和日志方面的清晰性而被选中)。
50
+ * **用户体验:** 优先考虑无缝和直观的用户体验,特别是对于交互式 CLI 工具。
51
+ * **可维护性:** 代码应保持整洁、结构良好且易于理解,以便于未来的维护。
52
+ * **文档语言:** `README.md` 等面向用户的文档应提供中英文双语说明,以覆盖更广泛的用户群体。
53
+ * **文档语言:** `README.md` 等面向用户的文档应提供中英文双语说明,以覆盖更广泛的用户群体。
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ai-cli-log
2
2
 
3
- Seamlessly log your AI-powered coding conversations. This command-line interface (CLI) tool captures your terminal interactions with AI models like Gemini and Claude, saving entire sessions as clean Markdown documents for easy review and documentation.
3
+ Seamlessly log your AI-powered coding conversations. This command-line interface (CLI) tool captures your terminal interactions with AI models like Gemini and Claude, saving entire sessions as clean plain text documents for easy review and documentation.
4
4
 
5
5
  ## Installation
6
6
 
@@ -10,7 +10,7 @@ npm install -g ai-cli-log
10
10
 
11
11
  ## Usage
12
12
 
13
- Wrap any command with `ai-cli-log` to start a logging session. The session will be saved to a Markdown file in the `.ai-cli-logs` directory.
13
+ Wrap any command with `ai-cli-log` to start a logging session. The session will be saved to a plain text file in the `.ai-cli-logs` directory.
14
14
 
15
15
  For example, to log a session with Google's Gemini CLI (`gemini`):
16
16
 
@@ -18,26 +18,39 @@ For example, to log a session with Google's Gemini CLI (`gemini`):
18
18
  ai-cli-log gemini
19
19
  ```
20
20
 
21
- Or to log a session with another tool, like `claude`:
21
+ Or to log a session with another tool, like `claude`:`
22
22
 
23
23
  ```bash
24
24
  ai-cli-log claude
25
25
  ```
26
26
 
27
- The recorded session will be saved to a file like `.ai-cli-logs/session-YYYYMMDD-HH:mm:ss.md`.
27
+ The recorded session will be saved to a file like `.ai-cli-logs/session-YYYYMMDD-HH:mm:ss.txt`.
28
28
 
29
29
  ## Features
30
30
 
31
31
  * **Interactive Session Capture:** Acts as a wrapper for other CLI tools, capturing full interactive sessions, including user input and the "rendered" output (what you actually see on the terminal after backspaces, cursor movements, etc.).
32
32
  * **Accurate Logging:** Utilizes `node-pty` for pseudo-terminal emulation and `@xterm/headless` to parse ANSI escape codes, ensuring the captured log accurately reflects the final state of the terminal screen.
33
- * **Markdown Output:** Saves recorded sessions as clean Markdown files for easy readability and documentation.
33
+ * **Plain Text Output:** Saves recorded sessions as clean plain text files for easy readability and documentation.
34
34
  * **TypeScript Implementation:** Built with Node.js and TypeScript, leveraging a robust ecosystem for CLI development and type safety.
35
35
 
36
+ ## Development Notes
37
+
38
+ This project was generated with the assistance of Google Gemini. You can review the detailed development process and interactions in the `.ai-cli-logs` directory, specifically starting with `0001.md` and subsequent log files.
39
+
40
+ Special thanks to Gemini for its invaluable help in the development of this tool!
41
+
42
+ ## TODO
43
+
44
+ * **Content Handling:**
45
+ * Empty log files are now prevented from being saved when the session output is blank or contains only whitespace.
46
+ * Trailing whitespace and blank lines are now trimmed from the output to address issues where insufficient content led to large blank areas.
47
+ * **Filename Convention:** The current timestamp-based filenames are functional but can be monotonous. Evaluate alternatives for more descriptive filenames, while carefully considering potential information leakage if AI summarization were to be used for naming.
48
+
36
49
  ---
37
50
 
38
51
  # ai-cli-log (中文说明)
39
52
 
40
- 无缝记录您与 AI 进行的编程对话。本命令行工具 (CLI) 能捕获您在终端中与 Gemini、Claude 等 AI 模型的交互过程,并将整个会话保存为清晰的 Markdown 文档,便于后续查阅和归档。
53
+ 无缝记录您与 AI 进行的编程对话。本命令行工具 (CLI) 能捕获您在终端中与 Gemini、Claude 等 AI 模型的交互过程,并将整个会话保存为清晰的纯文本文档,便于后续查阅和归档。
41
54
 
42
55
  ## 安装
43
56
 
@@ -61,7 +74,7 @@ ai-cli-log gemini
61
74
  ai-cli-log claude
62
75
  ```
63
76
 
64
- 记录的会话将保存为类似 `.ai-cli-logs/session-YYYYMMDD-HH:mm:ss.md` 的文件。
77
+ 记录的会话将保存为类似 `.ai-cli-logs/session-YYYYMMDD-HH:mm:ss.txt` 的文件。
65
78
 
66
79
  ## 快捷提示:使用别名
67
80
 
@@ -82,5 +95,18 @@ gemini-log
82
95
 
83
96
  * **交互式会话捕获:** 作为其他 CLI 工具的包装器,能够捕获完整的交互式会话,包括用户输入和最终“渲染”在屏幕上的输出(即处理了退格、光标移动等控制字符后的真实显示内容)。
84
97
  * **精确日志记录:** 利用 `node-pty` 进行伪终端模拟,并结合 `@xterm/headless` 解析 ANSI 转义码,确保日志精确还原终端的最终显示状态。
85
- * **Markdown 输出:** 将会话保存为干净、易读的 Markdown 文件,方便查阅和整理。
86
- * **TypeScript 实现:** 基于 Node.js 和 TypeScript 构建,确保了代码的健壮性和类型安全。
98
+ * **纯文本输出:** 将会话保存为干净、易读的纯文本文件,方便查阅和整理。
99
+ * **TypeScript 实现:** 基于 Node.js 和 TypeScript 构建,确保了代码的健壮性和类型安全。
100
+
101
+ ## 开发说明
102
+
103
+ 本项目是在 Google Gemini 的协助下生成的。您可以在 `.ai-cli-logs` 目录中查看详细的开发过程和交互记录,特别是从 `0001.md` 开始的日志文件。
104
+
105
+ 特别感谢 Gemini 在本项目开发过程中提供的宝贵帮助!
106
+
107
+ ## 待办事项 (TODO)
108
+
109
+ * **内容处理:**
110
+ * 当会话输出为空时,避免保存空的日志文件。
111
+ * 解决内容不足导致输出中出现大片空白的问题。
112
+ * **文件名约定:** 当前基于时间戳的文件名虽然功能上可行,但可能过于单调。评估其他更具描述性的文件名方案,同时仔细考虑如果使用 AI 摘要进行命名可能导致的信息泄露问题。
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ai-cli-log",
3
- "version": "1.0.1",
4
- "description": "Seamlessly log your AI-powered coding conversations. This command-line interface (CLI) tool captures your terminal interactions with AI models like Gemini and Claude, saving entire sessions as clean Markdown documents for easy review and documentation.",
3
+ "version": "1.0.2",
4
+ "description": "Seamlessly log your AI-powered coding conversations. This command-line interface (CLI) tool captures your terminal interactions with AI models like Gemini and Claude, saving entire sessions as clean plain text documents for easy review and documentation.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
7
  "ai-cli-log": "bin/ai-cli-log.js"
package/src/index.ts CHANGED
@@ -18,17 +18,20 @@ if (!fs.existsSync(logsDir)) {
18
18
  }
19
19
 
20
20
  // Initialize xterm.js in headless mode
21
+ const defaultRows = 24;
22
+ const defaultCols = 80;
23
+
21
24
  const xterm = new Terminal({
22
- rows: process.stdout.rows,
23
- cols: process.stdout.columns,
25
+ rows: process.stdout.rows || defaultRows,
26
+ cols: process.stdout.columns || defaultCols,
24
27
  scrollback: Infinity, // Set scrollback to Infinity for unlimited buffer
25
28
  allowProposedApi: true,
26
29
  });
27
30
 
28
31
  const term = pty.spawn(command, commandArgs, {
29
32
  name: 'xterm-color',
30
- cols: process.stdout.columns,
31
- rows: process.stdout.rows,
33
+ cols: process.stdout.columns || defaultCols,
34
+ rows: process.stdout.rows || defaultRows,
32
35
  cwd: process.cwd(),
33
36
  env: process.env as { [key: string]: string; },
34
37
  });
@@ -40,29 +43,37 @@ term.onData((data) => {
40
43
  });
41
44
 
42
45
  // Pipe stdin to pty
43
- process.stdin.on('data', (data) => {
44
- term.write(data.toString());
45
- });
46
+ if (process.stdin.isTTY) {
47
+ process.stdin.on('data', (data) => {
48
+ term.write(data.toString());
49
+ });
46
50
 
47
- process.stdin.setRawMode(true);
48
- process.stdin.resume();
51
+ process.stdin.setRawMode(true);
52
+ process.stdin.resume();
53
+ }
49
54
 
50
55
  term.onExit(({ exitCode, signal }) => {
51
56
  // Add a small delay to ensure xterm.js has processed all output
52
57
  setTimeout(() => {
53
58
  // Extract rendered text from xterm.js buffer
54
- let renderedOutput = '';
59
+ let renderedOutputLines: string[] = [];
55
60
  // Iterate over the entire buffer, including scrollback.
56
61
  // The total number of lines is the sum of lines in scrollback (baseY) and visible rows.
57
62
  for (let i = 0; i < xterm.buffer.active.baseY + xterm.rows; i++) {
58
63
  const line = xterm.buffer.active.getLine(i);
59
64
  if (line) {
60
65
  // translateToString(true) gets the line content, and we trim trailing whitespace.
61
- const lineText = line.translateToString(true).replace(/\s+$/, '');
62
- renderedOutput += lineText + '\n';
66
+ renderedOutputLines.push(line.translateToString(true));
63
67
  }
64
68
  }
65
69
 
70
+ // Remove trailing blank lines
71
+ while (renderedOutputLines.length > 0 && renderedOutputLines[renderedOutputLines.length - 1].trim() === '') {
72
+ renderedOutputLines.pop();
73
+ }
74
+
75
+ const renderedOutput = renderedOutputLines.join('\n');
76
+
66
77
  const now = new Date();
67
78
  const year = now.getFullYear();
68
79
  const month = (now.getMonth() + 1).toString().padStart(2, '0');
@@ -71,9 +82,16 @@ term.onExit(({ exitCode, signal }) => {
71
82
  const minutes = now.getMinutes().toString().padStart(2, '0');
72
83
  const seconds = now.getSeconds().toString().padStart(2, '0');
73
84
  const prefix = command || 'session';
74
- const logFileName = `${prefix}-${year}${month}${day}-${hours}${minutes}${seconds}.md`;
85
+ const logFileName = `${prefix}-${year}${month}${day}-${hours}${minutes}${seconds}.txt`;
86
+
75
87
  const logFilePath = path.join(logsDir, logFileName);
76
88
 
89
+ if (renderedOutput.trim().length === 0) {
90
+ console.log('Session had no output, not saving log file.');
91
+ process.exit(exitCode);
92
+ return;
93
+ }
94
+
77
95
  fs.writeFile(logFilePath, renderedOutput, (err: NodeJS.ErrnoException | null) => {
78
96
  if (err) {
79
97
  console.error('Error writing log file:', err);