change-log-agent 1.0.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Jesse Vincent
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # 🤖 log-agent
2
+
3
+ > **"讓 AI 成為你的專案文件官:一鍵同步 Git Commit 到高品質開發文件。"**
4
+
5
+ `log-agent` 是一款基於 **Agentic Workflow** 設計的 CLI 工具。它不只是簡單的文字搬運工,而是透過驅動你本地的 **Claude Code** 實例,將混亂的 Git Commit 歷史轉化為結構清晰、具備「人味」的專案文件(如 README 或 CHANGELOG)。
6
+
7
+ ---
8
+
9
+ ## ✨ 核心亮點
10
+
11
+ - **💰 零 API 成本**:直接利用你現有的 Claude Pro/Team 訂閱,無需支付額外 API Tokens 費用。
12
+ - **🧠 代理人架構 (Agentic Workflow)**:CLI 會動態生成任務規範(Mission Spec),指揮 AI 自主決定如何最佳化文件內容。
13
+ - **🎯 Surgical 級精準修改**:透過 HTML 註釋標記(`<!-- log-agent-start -->` / `<!-- log-agent-end -->`)定位,確保 AI 只修改授權區塊,絕不破壞你的原始文件排版。
14
+ - **⚙️ 語境感知 (Context-Aware)**:自動過濾碎屑 Commit(如 typo、formatting),並根據專案背景(如:官網重構)進行智能歸納。
15
+
16
+ ---
17
+
18
+ ## 🛠️ 運作原理
19
+
20
+ 1. **萃取 (Extract)**:CLI 自動掃描 Git 歷史,鎖定自上次版本以來的變更。
21
+ 2. **策劃 (Plan)**:根據專案現狀動態生成一份暫時的 `.claudemd.tmp` 任務規範。
22
+ 3. **執行 (Execute)**:啟動 `claude-code` 擔任「執行官」,依照規範對目標檔案進行智能手術。
23
+ 4. **清理 (Cleanup)**:任務完成後自動銷毀暫存檔,不留痕跡。
24
+
25
+ ---
26
+
27
+ ## 🚀 快速開始
28
+
29
+ ### 1. 前置要求
30
+
31
+ - 已安裝 **Node.js** (v18+)
32
+ - 已安裝並登入 **Claude Code**:
33
+
34
+ ```bash
35
+ npm install -g @anthropic-ai/claude-code
36
+ claude login
37
+ ```
38
+
39
+ ### 2. 安裝與開發
40
+
41
+ ```bash
42
+ # 克隆專案
43
+ git clone https://github.com/your-username/log-agent.git
44
+ cd log-agent
45
+
46
+ # 安裝依賴
47
+ npm install
48
+
49
+ # 編譯
50
+ npm run build
51
+ ```
52
+
53
+ ### 3. 初始化目標文件
54
+
55
+ 在你的 `README.md` 或 `CHANGELOG.md` 中加入以下標記:
56
+
57
+ ```markdown
58
+ ## 📝 更新日誌
59
+
60
+ <!-- log-agent-start -->
61
+ <!-- log-agent-end -->
62
+ ```
63
+
64
+ ### 4. 執行同步
65
+
66
+ ```bash
67
+ # 使用本地開發版本測試
68
+ npx ts-node src/index.ts sync
69
+ ```
70
+
71
+ ---
72
+
73
+ ## 📂 專案結構
74
+
75
+ - `src/core/git.ts`:負責處理 Git 指令與 Log 提取。
76
+ - `src/core/template.ts`:動態任務規範 (Mission Spec) 生成器。
77
+ - `src/index.ts`:CLI 入口與流程調度中心。
78
+
79
+ ---
80
+
81
+ ## 🤝 貢獻與開發
82
+
83
+ 本專案目前專注於與 `claude-code` 的深度整合。如果你有任何關於 Prompt 優化或跨平台相容性的建議,歡迎提交 Issue 或 Pull Request!
84
+
85
+ ---
86
+
87
+ License
88
+
89
+ MIT License - see LICENSE file for details
package/dist/index.mjs ADDED
@@ -0,0 +1,171 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import chalk from "chalk";
4
+ import { execa } from "execa";
5
+ import { readFile } from "node:fs/promises";
6
+
7
+ //#region src/core/git.ts
8
+ /**
9
+ * 擷取 git log 並 parse 成結構化資料
10
+ * @param since - ISO date string, e.g. "2026-02-01"
11
+ */
12
+ async function getCommits(since) {
13
+ const { stdout } = await execa("git", [
14
+ "log",
15
+ "--pretty=format:%h|%an|%ai|%s",
16
+ ...since ? [`--since=${since}`] : []
17
+ ]);
18
+ if (!stdout.trim()) return [];
19
+ return stdout.trim().split("\n").map(parseLine);
20
+ }
21
+ function parseLine(line) {
22
+ const parts = line.split("|");
23
+ const hash = parts[0] ?? "";
24
+ const author = parts[1] ?? "";
25
+ const dateRaw = parts[2] ?? "";
26
+ const message = parts[3] ?? "";
27
+ return {
28
+ hash,
29
+ author,
30
+ date: dateRaw.slice(0, 10),
31
+ message,
32
+ type: extractType(message)
33
+ };
34
+ }
35
+ function extractType(message) {
36
+ return message.match(/^(\w+)(?:\(.+?\))?:/)?.[1] ?? "other";
37
+ }
38
+
39
+ //#endregion
40
+ //#region src/core/template.ts
41
+ function buildMissionSpec(commits, targetFile) {
42
+ const commitBlock = commits.map((c) => `- \`${c.hash}\` ${c.message} (${c.author}, ${c.date})`).join("\n");
43
+ return {
44
+ prompt: [
45
+ `You are a documentation update assistant. Update the changelog section in ${targetFile} based on the following git commits.`,
46
+ "",
47
+ "## Rules",
48
+ "1. Only modify content between `<!-- log-agent-start -->` and `<!-- log-agent-end -->` markers",
49
+ "2. Group commits by date, most recent first",
50
+ "3. Each commit should be a single bullet point with a type badge",
51
+ "4. Do not modify anything outside the markers",
52
+ "5. Write in the same language as the existing document",
53
+ "",
54
+ "## Commits",
55
+ commitBlock,
56
+ "",
57
+ "## Output format example",
58
+ "```markdown",
59
+ "### 2026-02-05",
60
+ "- **feat** Implement FilePreview component with transition effects (`8a2f3b4`)",
61
+ "- **fix** Adjust MobileMenu padding for better responsiveness (`4d1e9a2`)",
62
+ "```",
63
+ "",
64
+ `Directly edit ${targetFile}. Do not output any explanation.`
65
+ ].join("\n"),
66
+ targetFile
67
+ };
68
+ }
69
+
70
+ //#endregion
71
+ //#region src/core/bridge.ts
72
+ async function executeMission(spec) {
73
+ try {
74
+ const { stdout } = await execa("claude", [
75
+ "-p",
76
+ "--allowedTools",
77
+ ["Read", "Edit"].join(",")
78
+ ], {
79
+ input: spec.prompt,
80
+ timeout: 6e4
81
+ });
82
+ return {
83
+ success: true,
84
+ output: stdout
85
+ };
86
+ } catch (error) {
87
+ const message = error instanceof Error ? error.message : "Unknown error occurred";
88
+ throw new Error(`claude -p execution failed: ${message}`);
89
+ }
90
+ }
91
+
92
+ //#endregion
93
+ //#region src/core/marker.ts
94
+ const START_TAG = "<!-- log-agent-start -->";
95
+ const END_TAG = "<!-- log-agent-end -->";
96
+ async function checkMarkers(filePath) {
97
+ try {
98
+ const content = await readFile(filePath, "utf-8");
99
+ const hasStart = content.includes(START_TAG);
100
+ const hasEnd = content.includes(END_TAG);
101
+ const lastDate = hasStart && hasEnd ? extractLastDate(content) : void 0;
102
+ return {
103
+ found: hasStart && hasEnd,
104
+ lastDate,
105
+ startTag: START_TAG,
106
+ endTag: END_TAG
107
+ };
108
+ } catch {
109
+ return {
110
+ found: false,
111
+ lastDate: void 0,
112
+ startTag: START_TAG,
113
+ endTag: END_TAG
114
+ };
115
+ }
116
+ }
117
+ function extractLastDate(content) {
118
+ const startIdx = content.indexOf(START_TAG);
119
+ const endIdx = content.indexOf(END_TAG);
120
+ if (startIdx === -1 || endIdx === -1) return void 0;
121
+ return [...content.slice(startIdx, endIdx).matchAll(/###\s+(\d{4}-\d{2}-\d{2})/g)].map((m) => m[1]).filter((d) => d !== void 0).sort().at(-1);
122
+ }
123
+
124
+ //#endregion
125
+ //#region src/index.ts
126
+ const program = new Command();
127
+ program.name("log-agent").description("AI-Powered Agentic Documentation CLI").version("0.1.0");
128
+ program.command("sync").description("Sync git log to documentation").option("--since <date>", "Only include commits after this date (e.g. 2026-02-01)").option("--target <file>", "Target file to update", "README.md").option("--dry-run", "Preview the mission spec without executing", false).action(async (options) => {
129
+ const { target: targetFile, since, dryRun } = options;
130
+ try {
131
+ console.log(chalk.blue("Starting log-agent sync..."));
132
+ const markers = await checkMarkers(targetFile);
133
+ if (!dryRun && !markers.found) {
134
+ console.error(chalk.red(`Markers not found in ${targetFile}.`));
135
+ console.error(chalk.gray(`Add these lines to your file:\n ${markers.startTag}\n ${markers.endTag}`));
136
+ process.exitCode = 1;
137
+ return;
138
+ }
139
+ const effectiveSince = since ?? markers.lastDate;
140
+ if (effectiveSince) console.log(chalk.gray(`Fetching commits since ${effectiveSince}`));
141
+ const commits = await getCommits(effectiveSince);
142
+ if (commits.length === 0) {
143
+ console.log(chalk.yellow("No commits found, skipping sync."));
144
+ return;
145
+ }
146
+ console.log(chalk.gray(`Found ${commits.length} commit(s)`));
147
+ const spec = buildMissionSpec(commits, targetFile);
148
+ if (dryRun) {
149
+ console.log(chalk.yellow("--- Dry Run: Mission Spec ---"));
150
+ console.log(spec.prompt);
151
+ console.log(chalk.yellow("--- End ---"));
152
+ return;
153
+ }
154
+ console.log(chalk.gray("Mission spec generated, invoking claude -p..."));
155
+ const result = await executeMission(spec);
156
+ console.log(chalk.green("Sync completed successfully."));
157
+ console.log(chalk.gray(result.output));
158
+ } catch (error) {
159
+ const message = error instanceof Error ? error.message : "Unknown error";
160
+ if (message.includes("ENOENT") && message.includes("claude")) {
161
+ console.error(chalk.red("Claude Code is not installed."));
162
+ console.error(chalk.gray("Run: npm install -g @anthropic-ai/claude-code"));
163
+ } else if (message.includes("not a git repository")) console.error(chalk.red("Not a git repository."));
164
+ else console.error(chalk.red(`Sync failed: ${message}`));
165
+ process.exitCode = 1;
166
+ }
167
+ });
168
+ program.parse();
169
+
170
+ //#endregion
171
+ export { };
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "change-log-agent",
3
+ "version": "1.0.0",
4
+ "description": "AI-powered CLI that syncs git commit history to project documentation via Claude Code",
5
+ "type": "module",
6
+ "main": "dist/index.mjs",
7
+ "bin": {
8
+ "log-agent": "dist/index.mjs"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsdown",
15
+ "prepublishOnly": "npm run build",
16
+ "test": "vitest run"
17
+ },
18
+ "keywords": [
19
+ "cli",
20
+ "git",
21
+ "changelog",
22
+ "documentation",
23
+ "claude",
24
+ "ai"
25
+ ],
26
+ "author": "Eric Cai",
27
+ "license": "MIT",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/ericcai0814/log-agent.git"
31
+ },
32
+ "dependencies": {
33
+ "chalk": "^5.6.2",
34
+ "commander": "^14.0.3",
35
+ "execa": "^9.6.1"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^25.2.0",
39
+ "@vitest/coverage-v8": "^4.0.18",
40
+ "tsdown": "^0.20.3",
41
+ "typescript": "^5.9.3",
42
+ "vitest": "^4.0.18"
43
+ }
44
+ }