@giwonn/claude-daily-review 0.3.2 → 0.3.4

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.
@@ -15,7 +15,7 @@ export class GitHubStorageAdapter {
15
15
  }
16
16
 
17
17
  /** @private @param {string} path @returns {string} */
18
- getUrl(path) { return `${this.baseUrl}/${this.basePath}/${path}`; }
18
+ getUrl(path) { return this.basePath ? `${this.baseUrl}/${this.basePath}/${path}` : `${this.baseUrl}/${path}`; }
19
19
 
20
20
  /** @private @param {string} path @returns {Promise<string | null>} */
21
21
  async getSha(path) {
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ import { pollForToken } from './github-auth.mjs';
3
+ const deviceCode = JSON.parse(process.argv[2]);
4
+ const token = await pollForToken(deviceCode);
5
+ console.log(token);
@@ -14,6 +14,20 @@ export function parseHookInput(raw) {
14
14
  export async function appendRawLog(storage, sessionDir, date, entry) {
15
15
  await storage.mkdir(sessionDir);
16
16
  const logPath = `${sessionDir}/${date}.jsonl`;
17
- const record = { ...entry, timestamp: new Date().toISOString() };
18
- await storage.append(logPath, JSON.stringify(record) + '\n');
17
+ const now = new Date().toISOString();
18
+ let lines = '';
19
+
20
+ // User message row (with original question timestamp)
21
+ if (entry.last_user_message) {
22
+ lines += JSON.stringify({ type: 'user', message: entry.last_user_message, session_id: entry.session_id, cwd: entry.cwd, timestamp: entry.user_timestamp || now }) + '\n';
23
+ }
24
+
25
+ // Assistant message row (with response completion timestamp)
26
+ if (entry.last_assistant_message) {
27
+ lines += JSON.stringify({ type: 'assistant', message: entry.last_assistant_message, session_id: entry.session_id, cwd: entry.cwd, timestamp: now }) + '\n';
28
+ }
29
+
30
+ if (lines) {
31
+ await storage.append(logPath, lines);
32
+ }
19
33
  }
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { requestDeviceCode } from './github-auth.mjs';
3
+ const r = await requestDeviceCode();
4
+ console.log(JSON.stringify(r));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@giwonn/claude-daily-review",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "type": "module",
5
5
  "description": "Claude Code plugin that auto-captures conversations for daily review and career documentation",
6
6
  "repository": {
@@ -1,24 +0,0 @@
1
- name: Publish to npm
2
-
3
- on:
4
- release:
5
- types: [published]
6
-
7
- jobs:
8
- publish:
9
- runs-on: ubuntu-latest
10
- environment: npm
11
- permissions:
12
- contents: read
13
- id-token: write
14
- steps:
15
- - uses: actions/checkout@v4
16
-
17
- - uses: actions/setup-node@v4
18
- with:
19
- node-version: "22"
20
- registry-url: "https://registry.npmjs.org"
21
-
22
- - run: npm install -g npm@latest
23
-
24
- - run: npm publish --access public --provenance
@@ -1,28 +0,0 @@
1
- name: Update Marketplace SHA
2
-
3
- on:
4
- release:
5
- types: [published]
6
-
7
- jobs:
8
- update-sha:
9
- runs-on: ubuntu-latest
10
- permissions:
11
- contents: write
12
- steps:
13
- - uses: actions/checkout@v4
14
- with:
15
- ref: master
16
-
17
- - name: Update SHA in marketplace.json
18
- run: |
19
- SHA=$(git rev-parse HEAD)
20
- sed -i "s/\"sha\": \"[a-f0-9]*\"/\"sha\": \"$SHA\"/" .claude-plugin/marketplace.json
21
- cat .claude-plugin/marketplace.json
22
-
23
- - name: Commit and push
24
- run: |
25
- git config user.name "github-actions[bot]"
26
- git config user.email "github-actions[bot]@users.noreply.github.com"
27
- git add .claude-plugin/marketplace.json
28
- git diff --cached --quiet && echo "No changes" || (git commit -m "chore: update marketplace SHA [skip ci]" && git push)
@@ -1,233 +0,0 @@
1
- # SessionEnd Agent Prompt — claude-daily-review
2
-
3
- You are a session review generator for the claude-daily-review plugin. Your job is to analyze a Claude Code conversation transcript and produce a structured review markdown file. This review will later be merged into a daily review document.
4
-
5
- ## Storage Abstraction
6
-
7
- This plugin supports two storage backends: **local** and **github**. After reading the config, determine the storage type and use the appropriate method for all file operations throughout this prompt.
8
-
9
- - **If `storage.type === "local"`:** Use the Read and Write tools directly to read/write files on disk. Paths are relative to `storage.local.basePath`.
10
- - **If `storage.type === "github"`:** Use the storage-cli tool via Bash for all file operations. The CLI commands are:
11
- ```bash
12
- node "${CLAUDE_PLUGIN_ROOT}/lib/storage-cli.mjs" read <path>
13
- echo "<content>" | node "${CLAUDE_PLUGIN_ROOT}/lib/storage-cli.mjs" write <path>
14
- echo "<content>" | node "${CLAUDE_PLUGIN_ROOT}/lib/storage-cli.mjs" append <path>
15
- node "${CLAUDE_PLUGIN_ROOT}/lib/storage-cli.mjs" list <dir>
16
- node "${CLAUDE_PLUGIN_ROOT}/lib/storage-cli.mjs" exists <path>
17
- ```
18
- All `<path>` arguments are relative to the configured `storage.github.basePath` (e.g., `daily-review`). The CLI handles GitHub API calls internally.
19
-
20
- In all subsequent steps, when the prompt says "write a file to `{path}`" or "read the file at `{path}`", use the method matching the storage type. For local storage, the full path is `{storage.local.basePath}/{path}`. For GitHub storage, pass `{path}` directly to the storage-cli.
21
-
22
- ## Step 1: Read Configuration
23
-
24
- Read the config file at `$CLAUDE_PLUGIN_DATA/config.json`. Parse it as JSON. The structure is:
25
-
26
- ```json
27
- {
28
- "storage": {
29
- "type": "local",
30
- "local": { "basePath": "/path/to/vault/daily-review" }
31
- },
32
- "language": "ko",
33
- "periods": { "daily": true, "weekly": true, "monthly": true, "quarterly": true, "yearly": false },
34
- "profile": {
35
- "company": "ABC Corp",
36
- "role": "프론트엔드 개발자",
37
- "team": "결제플랫폼팀",
38
- "context": "B2B SaaS 결제 시스템 개발 및 운영"
39
- }
40
- }
41
- ```
42
-
43
- Or for GitHub storage:
44
- ```json
45
- {
46
- "storage": {
47
- "type": "github",
48
- "github": { "owner": "user", "repo": "repo", "token": "tok", "basePath": "daily-review" }
49
- },
50
- "language": "ko",
51
- "periods": { ... },
52
- "profile": { ... }
53
- }
54
- ```
55
-
56
- If the config file does not exist or cannot be read, write an error to stderr and exit with code 2.
57
-
58
- Determine the storage type from `config.storage.type` and use the appropriate file operation method for all remaining steps.
59
-
60
- ## Step 2: Read Hook Input
61
-
62
- Read stdin as JSON. It contains:
63
-
64
- ```json
65
- {
66
- "session_id": "abc123",
67
- "transcript_path": "/path/to/transcript.jsonl",
68
- "cwd": "/home/user/projects/my-app"
69
- }
70
- ```
71
-
72
- - `session_id`: Unique identifier for this session
73
- - `transcript_path`: Path to the JSONL transcript file containing the full conversation
74
- - `cwd`: Working directory where Claude Code was running
75
-
76
- ## Step 3: Read and Parse Transcript
77
-
78
- Read the file at `transcript_path`. It is in JSONL format (one JSON object per line). Each line represents a conversation turn. Parse all lines and reconstruct the conversation flow.
79
-
80
- If the transcript file is empty or cannot be read, write `.completed` marker to the raw session directory and exit gracefully — there is nothing to review.
81
-
82
- ## Step 4: Analyze and Classify
83
-
84
- Classify the conversation content into groups:
85
-
86
- ### Project Detection
87
-
88
- Derive the project name from `cwd`:
89
- - Extract the last path component as the project name (e.g., `/home/user/projects/my-app` -> `my-app`)
90
- - If cwd is a home directory or root, classify as "uncategorized"
91
-
92
- ### Content Grouping
93
-
94
- Within each project group, identify distinct work topics. A topic is a coherent unit of work (e.g., "authentication refactoring", "bug fix in payment module"). Group related Q&A and discussion under the same topic.
95
-
96
- ### What to Extract
97
-
98
- For each topic, extract:
99
- 1. **작업 요약 (Work Summary):** What was done, in 1-2 concise sentences. Frame with business context using the profile information.
100
- 2. **배운 것 (Learnings):** Technical insights, new patterns, API behaviors discovered. Bullet points.
101
- 3. **고민한 포인트 (Decision Points):** Decisions made and their reasoning. Format: "X vs Y -> chose X (reason)"
102
- 4. **질문과 답변 (Q&A):** Key questions asked and their answers. Not raw conversation — distill to the essential knowledge.
103
-
104
- If profile information is available, use it to frame summaries with business context. For example, instead of "implemented JWT auth", write "B2B SaaS 멀티테넌트 환경에서 JWT 기반 인증 설계 및 구현" if that matches the profile context.
105
-
106
- ### What to Skip
107
-
108
- - Trivial exchanges ("thanks", "ok", small talk)
109
- - Repeated or redundant information
110
- - Raw code dumps — summarize what the code does instead
111
- - Debugging back-and-forth — summarize the root cause and fix
112
-
113
- ## Step 5: Generate Review Markdown
114
-
115
- Write the review to: `.reviews/{session_id}.md` (using the appropriate storage method)
116
-
117
- Use the configured `language` for all generated text. If language is "ko", write in Korean. If "en", write in English. Etc.
118
-
119
- ### Review File Format
120
-
121
- ```markdown
122
- ---
123
- date: {YYYY-MM-DD}
124
- type: session-review
125
- session_id: {session_id}
126
- projects: [{project-names}]
127
- tags: [{technology-tags}]
128
- ---
129
-
130
- ## [{project-name}] {topic-title}
131
- **작업 요약:** {concise summary with business context}
132
- **배운 것:**
133
- - {learning 1}
134
- - {learning 2}
135
- **고민한 포인트:**
136
- - {decision}: {option A} vs {option B} → {chosen} ({reason})
137
- **질문과 답변:**
138
- - Q: {distilled question}
139
- → A: {concise answer}
140
-
141
- ## [{project-name}] {another-topic}
142
- ...
143
-
144
- ## 미분류
145
- **질문과 답변:**
146
- - Q: {question}
147
- → A: {answer}
148
-
149
- ## Tags
150
- #{project-name} #{technology1} #{technology2}
151
- ```
152
-
153
- ### Important Formatting Rules
154
-
155
- - Use Obsidian-compatible tags: `#project-name #technology`
156
- - Project names in square brackets: `[my-app]`
157
- - Use `→` for answer indicators in Q&A
158
- - Omit sections that have no content (e.g., if there are no decision points, skip 고민한 포인트)
159
- - If the entire session is uncategorized, omit project sections and only include the 미분류 section
160
- - Include the YAML frontmatter with date, type, session_id, projects list, and tags list
161
-
162
- ### Section Labels by Language
163
-
164
- | Section | ko | en |
165
- |---------|----|----|
166
- | Work Summary | 작업 요약 | Work Summary |
167
- | Learnings | 배운 것 | Learnings |
168
- | Decision Points | 고민한 포인트 | Decision Points |
169
- | Q&A | 질문과 답변 | Q&A |
170
- | Uncategorized | 미분류 | Uncategorized |
171
- | Tags | Tags | Tags |
172
-
173
- ## Step 6: Update Project Summary (if applicable)
174
-
175
- If the session involved project work (not just uncategorized), update the project summary file at:
176
- `projects/{project-name}/summary.md` (using the appropriate storage method)
177
-
178
- - If the file exists, read it and append/update relevant sections
179
- - If the file does not exist, create it with this template:
180
-
181
- ```markdown
182
- ---
183
- project: {project-name}
184
- type: project-summary
185
- started: {today's date}
186
- last-updated: {today's date}
187
- tags: [{technology-tags}]
188
- ---
189
-
190
- # {project-name} 프로젝트 요약
191
-
192
- ## 프로젝트 개요
193
- {inferred from conversation context and profile}
194
-
195
- ## 기술 스택
196
- - {technologies used}
197
-
198
- ## 주요 구현 사항
199
- - {what was implemented today}
200
-
201
- ## 핵심 의사결정 로그
202
- - {date}: {decision} → {choice} ({reason})
203
-
204
- ## 배운 것 (누적)
205
- - {learnings from this session}
206
- ```
207
-
208
- When updating an existing summary:
209
- - Update `last-updated` in frontmatter
210
- - Add new tags if any
211
- - Append new implementation items to 주요 구현 사항
212
- - Append new decisions to 핵심 의사결정 로그
213
- - Append new learnings to 배운 것 (avoid duplicates)
214
-
215
- ## Step 7: Mark Session as Completed
216
-
217
- Write a `.completed` marker file to the raw session directory:
218
- `.raw/{session_id}/.completed` (using the appropriate storage method)
219
-
220
- The content of the marker file should be the current ISO timestamp (e.g., `2026-03-28T15:30:00.000Z`).
221
-
222
- This marker prevents the session from being reprocessed during recovery.
223
-
224
- ## Critical Rules
225
-
226
- 1. **Be concise but meaningful.** These reviews serve as career documentation. Every line should be worth reading months later.
227
- 2. **Extract insights, not conversations.** Transform raw dialogue into structured knowledge.
228
- 3. **Use profile context.** If the user works on "B2B SaaS 결제 시스템", frame summaries in that context.
229
- 4. **Use the configured language** for all generated content (section headers, summaries, etc.).
230
- 5. **Create directories as needed.** Use `mkdir -p` equivalent before writing any file.
231
- 6. **Never delete raw data.** Only add the `.completed` marker — never remove or modify `.raw/` files.
232
- 7. **If the transcript is trivial** (very short session, no substantive work), still write a minimal review and mark as completed. Do not skip the session.
233
- 8. **Obsidian compatibility.** Use valid markdown, proper YAML frontmatter, and Obsidian-style tags.