@albireo3754/agentlog 0.1.1 → 0.1.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/README.md CHANGED
@@ -1,14 +1,18 @@
1
1
  # AgentLog
2
2
 
3
- Claude Code prompts Obsidian Daily Note, automatically.
3
+ Auto-log Claude Code prompts to Obsidian Daily Notes.
4
4
 
5
- Every time you type a prompt in Claude Code, AgentLog captures it and appends it to your Obsidian Daily Note — with timestamps, grouped by project and session.
5
+ AgentLog is a local-first Claude Code prompt logger for Obsidian. It captures every prompt you type in Claude Code and appends it to today's Daily Note, grouped by project and session.
6
6
 
7
- ```
8
- npx agentlog init ~/Obsidian
7
+ Use it as a lightweight developer journal, worklog capture layer, or the first building block for richer Daily Notes automation.
8
+
9
+ ```bash
10
+ # Requires Bun (https://bun.sh) installed and available on your PATH
11
+ npm install -g @albireo3754/agentlog
12
+ agentlog init ~/Obsidian
9
13
  ```
10
14
 
11
- That's it. Start using Claude Code and your Daily Note fills itself.
15
+ Install it once, start using Claude Code, and your Daily Note fills itself.
12
16
 
13
17
  ## What It Does
14
18
 
@@ -16,28 +20,35 @@ That's it. Start using Claude Code and your Daily Note fills itself.
16
20
  Claude Code prompt → UserPromptSubmit hook → Daily Note append
17
21
  ```
18
22
 
23
+ ## Why AgentLog
24
+
25
+ - Local-first prompt logging with no external service required
26
+ - Obsidian Daily Notes integration that works with your existing vault
27
+ - Project and session grouping so prompts stay readable later
28
+ - Zero copy-paste overhead during normal Claude Code use
29
+
19
30
  **Before:** You finish a 3-hour Claude Code session. Your Daily Note is empty.
20
31
 
21
32
  **After:**
22
33
 
23
34
  ```markdown
24
35
  ## AgentLog
25
- > 🕐 11:21 — js/agentlog › git init하고 vscode로 열어봐
36
+ > 🕐 11:21 — js/agentlog › initialize git and open it in VS Code
26
37
 
27
38
  #### 10:53 · js/agentlog
28
39
  <!-- cwd=/Users/you/work/js/agentlog -->
29
40
  - - - - [[ses_a1b2c3d4]]
30
- - 10:53 agentlog 개발을 위해서 작업 진행
31
- - 11:07 스펙 문서 열어봐
41
+ - 10:53 start building agentlog
42
+ - 11:07 open the spec document
32
43
  - - - - [[ses_e5f6a7b8]]
33
- - 11:21 git init하고 vscode로 열어봐
44
+ - 11:21 initialize git and open it in VS Code
34
45
  ```
35
46
 
36
47
  | Element | Role |
37
48
  |---------|------|
38
49
  | `> 🕐 HH:MM — project › prompt` | Latest entry (always updated) |
39
50
  | `#### HH:MM · project` | Project subsection (grouped by cwd) |
40
- | `<!-- cwd=... -->` | Section matching key (Reading view에서 숨김) |
51
+ | `<!-- cwd=... -->` | Section matching key (hidden in Obsidian Reading view) |
41
52
  | `- - - - [[ses_...]]` | Session boundary (Obsidian wiki-link) |
42
53
  | `- HH:MM prompt` | Individual log entry |
43
54
 
@@ -47,12 +58,17 @@ No manual logging. No copy-paste. No AI summarization overhead.
47
58
 
48
59
  ```bash
49
60
  # With Bun
50
- bunx agentlog init ~/path/to/vault
61
+ bun add -g @albireo3754/agentlog
51
62
 
52
63
  # With npm
53
- npx agentlog init ~/path/to/vault
64
+ npm install -g @albireo3754/agentlog
65
+
66
+ # Then configure your vault
67
+ agentlog init ~/path/to/vault
54
68
  ```
55
69
 
70
+ AgentLog registers the Claude Code hook as `agentlog hook`, so the `agentlog` binary must remain available on your `PATH` after setup.
71
+
56
72
  ### Requirements
57
73
 
58
74
  - [Claude Code](https://claude.ai/code) (hook integration)
@@ -86,7 +102,7 @@ Use Claude Code normally. Every prompt you type gets logged to your Daily Note.
86
102
  1. You type a prompt in Claude Code
87
103
  2. Claude Code fires the `UserPromptSubmit` hook
88
104
  3. AgentLog reads the prompt from stdin and sanitizes it
89
- 4. Finds your Daily Note via `obsidian daily:path` (Obsidian CLI 1.12+), fallback: `{vault}/Daily/YYYY-MM-DD-요일.md`
105
+ 4. Finds your Daily Note via `obsidian daily:path` (Obsidian CLI 1.12+). If that fails, it falls back to `{vault}/Daily/YYYY-MM-DD-<Korean weekday>.md`
90
106
  5. Finds or creates a `## AgentLog` section
91
107
  6. Finds or creates a `#### project` subsection matching the current working directory
92
108
  7. Inserts a session divider `[[ses_...]]` if the session changed, then appends the entry
@@ -98,25 +114,25 @@ Total overhead: < 50ms per prompt. Fire-and-forget, never blocks Claude Code.
98
114
 
99
115
  ### Obsidian Mode (default)
100
116
 
101
- Daily Note 경로는 `obsidian daily:path` CLI 명령으로 동적 해석 (Obsidian 1.12+). Obsidian 실행 중이 아니거나 CLI를 사용할 없으면 `{vault}/Daily/YYYY-MM-DD-요일.md`로 fallback.
117
+ AgentLog resolves the Daily Note path via `obsidian daily:path` when the Obsidian CLI is available (1.12+). If the CLI is unavailable or Obsidian is not running, it falls back to `{vault}/Daily/YYYY-MM-DD-<Korean weekday>.md` such as `2026-03-01-일.md`.
102
118
 
103
119
  Each working directory gets its own `#### project` subsection. Session changes insert a `[[ses_...]]` wiki-link divider. The `> 🕐` blockquote at the top always shows the latest entry across all projects.
104
120
 
105
121
  ```markdown
106
122
  ## AgentLog
107
- > 🕐 14:30 — kotlin/message-gate › API 응답 수정
123
+ > 🕐 14:30 — kotlin/message-gate › adjust the API response
108
124
 
109
125
  #### 10:53 · js/agentlog
110
126
  <!-- cwd=/Users/you/work/js/agentlog -->
111
127
  - - - - [[ses_a1b2c3d4]]
112
- - 10:53 agentlog 개발을 위해서 작업 진행
113
- - 11:07 스펙 문서 열어봐
128
+ - 10:53 start building agentlog
129
+ - 11:07 open the spec document
114
130
 
115
131
  #### 14:00 · kotlin/message-gate
116
132
  <!-- cwd=/Users/you/work/kotlin/message-gate -->
117
133
  - - - - [[ses_e5f6a7b8]]
118
- - 14:00 API 응답 수정
119
- - 14:30 테스트 실행
134
+ - 14:00 adjust the API response
135
+ - 14:30 run tests
120
136
  ```
121
137
 
122
138
  ### Plain Mode
@@ -125,19 +141,20 @@ With `--plain`, entries go to `{folder}/YYYY-MM-DD.md`:
125
141
 
126
142
  ```markdown
127
143
  # 2026-03-02
128
- - 10:53 agentlog 개발을 위해서 작업 진행
144
+ - 10:53 start building agentlog
129
145
  ```
130
146
 
131
147
  ## CLI Reference
132
148
 
133
149
  | Command | Description |
134
150
  |---------|-------------|
135
- | `agentlog init [vault] [--plain]` | Vault 경로 설정 + Claude Code hook 등록. 인자 없으면 자동 감지 |
136
- | `agentlog detect` | 설치된 Obsidian vault 목록 + CLI 상태 표시 |
137
- | `agentlog doctor` | 설치 상태 헬스체크 (binary, vault, hook, Obsidian CLI 등) |
138
- | `agentlog open` | 오늘의 Daily Note Obsidian에서 열기 (CLI 1.12+ 필요) |
139
- | `agentlog uninstall [-y]` | Hook 제거 + `~/.agentlog/` 삭제. `-y`로 확인 생략 |
140
- | `agentlog hook` | Claude Code가 자동 호출 (사용자 직접 실행 X) |
151
+ | `agentlog init [vault] [--plain]` | Configure the vault path and register the Claude Code hook. Auto-detect vaults when the path is omitted |
152
+ | `agentlog detect` | List detected Obsidian vaults and CLI status |
153
+ | `agentlog doctor` | Run health checks for the binary, vault, hook, and Obsidian CLI |
154
+ | `agentlog open` | Open today's Daily Note in Obsidian (requires CLI 1.12+) |
155
+ | `agentlog version` | Print AgentLog version. In `dev` builds, also shows channel and commit |
156
+ | `agentlog uninstall [-y]` | Remove the hook and delete `~/.agentlog/`. Use `-y` to skip confirmation |
157
+ | `agentlog hook` | Invoked automatically by Claude Code (not for direct use) |
141
158
 
142
159
  ## Configuration
143
160
 
@@ -145,15 +162,34 @@ With `--plain`, entries go to `{folder}/YYYY-MM-DD.md`:
145
162
 
146
163
  | Field | Default | Description |
147
164
  |-------|---------|-------------|
148
- | `vault` | (required) | Obsidian vault 또는 plain 폴더 경로 |
149
- | `plain` | `false` | Plain 모드 (Obsidian 없이 단순 파일 기록) |
165
+ | `vault` | (required) | Path to the Obsidian vault or plain output folder |
166
+ | `plain` | `false` | Plain mode that writes simple markdown files without Obsidian integration |
150
167
 
151
- 환경변수:
168
+ Environment variables:
152
169
 
153
170
  | Variable | Description |
154
171
  |----------|-------------|
155
- | `AGENTLOG_CONFIG_DIR` | Config 디렉토리 오버라이드 (기본: `~/.agentlog`) |
156
- | `OBSIDIAN_BIN` | Obsidian CLI 바이너리 경로 오버라이드 |
172
+ | `AGENTLOG_CONFIG_DIR` | Override the config directory (default: `~/.agentlog`) |
173
+ | `AGENTLOG_PHASE` | Force the runtime channel (`dev` or `prod`), overriding auto-detection |
174
+ | `OBSIDIAN_BIN` | Override the Obsidian CLI binary path |
175
+
176
+ `agentlog version`은 현재 실행 중인 AgentLog의 build identity를 출력합니다.
177
+
178
+ - `prod`: 헤드라인만 출력
179
+
180
+ ```text
181
+ AgentLog 0.1.1
182
+ ```
183
+
184
+ - `dev`: 개발 실행임을 나타내는 메타데이터를 추가 출력
185
+
186
+ ```text
187
+ AgentLog 0.1.1
188
+ channel: dev
189
+ commit: <short-sha>
190
+ ```
191
+
192
+ 기본 규칙은 git 메타데이터가 있는 checkout/link 실행이면 `dev`, 패키지 설치본이면 `prod`입니다. 테스트나 디버깅에서 channel을 고정하고 싶다면 `AGENTLOG_PHASE=dev` 또는 `AGENTLOG_PHASE=prod`를 사용할 수 있습니다.
157
193
 
158
194
  ## Uninstall
159
195
 
@@ -161,27 +197,27 @@ With `--plain`, entries go to `{folder}/YYYY-MM-DD.md`:
161
197
  agentlog uninstall
162
198
  ```
163
199
 
164
- Hook을 `~/.claude/settings.json`에서 제거하고 `~/.agentlog/`를 삭제합니다.
200
+ This removes the hook from `~/.claude/settings.json` and deletes `~/.agentlog/`.
165
201
 
166
202
  ## Development
167
203
 
168
204
  ```bash
169
205
  bun install
170
- bun test # 120 pass / 120 tests
171
- bun run typecheck # tsc --noEmit
206
+ bun test # run the test suite
207
+ bun run typecheck # run tsc --noEmit
172
208
  bun run build # compile to dist/ (optional)
173
209
  ```
174
210
 
175
- `bin`이 `src/cli.ts`를 직접 가리키므로 개발 빌드 불필요 Bun TypeScript 네이티브 실행합니다.
211
+ The `bin` entry points directly to `src/cli.ts`, so you do not need a build during development. Bun runs TypeScript natively.
176
212
 
177
213
  ```bash
178
- # 글로벌 커맨드로 링크
214
+ # Link as a global command
179
215
  bun link
180
216
 
181
- # 소스 수정 즉시 반영
217
+ # Edit source and run immediately
182
218
  agentlog doctor
183
219
 
184
- # Watch 모드
220
+ # Watch mode
185
221
  bun run dev:watch
186
222
  ```
187
223
 
package/package.json CHANGED
@@ -1,11 +1,28 @@
1
1
  {
2
2
  "name": "@albireo3754/agentlog",
3
- "version": "0.1.1",
4
- "description": "Claude Code prompts Obsidian Daily Note auto-logger",
3
+ "version": "0.1.2",
4
+ "description": "Auto-log Claude Code prompts to Obsidian Daily Notes",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "agentlog": "./src/cli.ts"
8
8
  },
9
+ "keywords": [
10
+ "claude-code",
11
+ "obsidian",
12
+ "daily-notes",
13
+ "prompt-logging",
14
+ "developer-journal",
15
+ "worklog",
16
+ "hook"
17
+ ],
18
+ "homepage": "https://github.com/albireo3754/agentlog#readme",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/albireo3754/agentlog.git"
22
+ },
23
+ "bugs": {
24
+ "url": "https://github.com/albireo3754/agentlog/issues"
25
+ },
9
26
  "scripts": {
10
27
  "build": "bun build src/cli.ts src/hook.ts --outdir dist --target node",
11
28
  "dev": "bun run src/cli.ts",
package/src/cli.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  * agentlog hook — invoked by Claude Code UserPromptSubmit hook
9
9
  */
10
10
 
11
- import { existsSync, readFileSync, rmSync } from "fs";
11
+ import { existsSync, rmSync } from "fs";
12
12
  import { join, resolve } from "path";
13
13
  import { homedir } from "os";
14
14
  import { spawnSync } from "child_process";
@@ -16,6 +16,7 @@ import { saveConfig, loadConfig, expandHome, configPath, configDir } from "./con
16
16
  import { detectVaults, detectCli } from "./detect.js";
17
17
  import { isVersionAtLeast, MIN_CLI_VERSION, resolveCliBin, parseCliVersion } from "./obsidian-cli.js";
18
18
  import { registerHook, unregisterHook, isHookRegistered, CLAUDE_SETTINGS_PATH } from "./claude-settings.js";
19
+ import { formatVersionHeadline, formatVersionOutput, getRuntimeInfo, readVersion, resolvePackageRoot } from "./version-info.js";
19
20
  import * as readline from "readline";
20
21
 
21
22
  function usage(): void {
@@ -25,6 +26,7 @@ function usage(): void {
25
26
  agentlog doctor Check installation health
26
27
  agentlog open Open today's Daily Note in Obsidian (CLI)
27
28
  agentlog uninstall Remove hook and config
29
+ agentlog version Print version and build identity
28
30
  agentlog hook Run hook (called by Claude Code)
29
31
 
30
32
  Options:
@@ -55,10 +57,10 @@ Warning: Obsidian vault not detected at: ${vault}
55
57
 
56
58
  1. Install Obsidian: https://obsidian.md/download
57
59
  2. Open the folder as a vault, then run:
58
- npx agentlog init /path/to/your/vault
60
+ agentlog init /path/to/your/vault
59
61
 
60
62
  Or to write to a plain folder:
61
- npx agentlog init --plain ~/notes
63
+ agentlog init --plain ~/notes
62
64
  `);
63
65
  process.exit(1);
64
66
  }
@@ -238,14 +240,8 @@ async function cmdUninstall(args: string[]): Promise<void> {
238
240
 
239
241
  /** agentlog doctor — check installation health */
240
242
  async function cmdDoctor(): Promise<void> {
241
- // Show agentlog version
242
- try {
243
- const pkgPath = join(import.meta.dir ?? new URL(".", import.meta.url).pathname, "..", "package.json");
244
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8")) as { version?: string };
245
- if (pkg.version) console.log(`agentlog v${pkg.version}\n`);
246
- } catch {
247
- // version display is best-effort
248
- }
243
+ const version = readVersion(resolvePackageRoot());
244
+ if (version) console.log(`${formatVersionHeadline({ version })}\n`);
249
245
 
250
246
  let allOk = true;
251
247
 
@@ -259,7 +255,12 @@ async function cmdDoctor(): Promise<void> {
259
255
  // 1. Binary in PATH
260
256
  const which = spawnSync("which", ["agentlog"], { encoding: "utf-8" });
261
257
  const binPath = which.status === 0 ? which.stdout.trim() : "";
262
- check("binary", !!binPath, binPath || "not found in PATH", "run: npm install -g agentlog");
258
+ check(
259
+ "binary",
260
+ !!binPath,
261
+ binPath || "not found in PATH",
262
+ "install agentlog globally (e.g. npm install -g @albireo3754/agentlog or bun install -g @albireo3754/agentlog)"
263
+ );
263
264
 
264
265
  // 2. Vault (covers both config presence and vault validity)
265
266
  const config = loadConfig();
@@ -390,6 +391,10 @@ async function cmdHook(): Promise<void> {
390
391
  await import("./hook.js");
391
392
  }
392
393
 
394
+ async function cmdVersion(): Promise<void> {
395
+ console.log(formatVersionOutput(getRuntimeInfo()));
396
+ }
397
+
393
398
  // --- Main dispatch ---
394
399
 
395
400
  const [, , command, ...rest] = process.argv;
@@ -410,6 +415,9 @@ switch (command) {
410
415
  case "uninstall":
411
416
  await cmdUninstall(rest);
412
417
  break;
418
+ case "version":
419
+ await cmdVersion();
420
+ break;
413
421
  case "hook":
414
422
  await cmdHook();
415
423
  break;
@@ -0,0 +1,106 @@
1
+ import { existsSync, readFileSync } from "fs";
2
+ import { spawnSync } from "child_process";
3
+ import { dirname, join, resolve } from "path";
4
+ import { fileURLToPath } from "url";
5
+
6
+ export type AgentlogChannel = "dev" | "prod";
7
+
8
+ export type RuntimeInfo = {
9
+ version: string | null;
10
+ channel: AgentlogChannel;
11
+ commit: string | null;
12
+ packageRoot: string;
13
+ };
14
+
15
+ type RuntimeInfoOptions = {
16
+ env?: Record<string, string | undefined>;
17
+ packageRoot?: string;
18
+ moduleDir?: string;
19
+ };
20
+
21
+ function currentModuleDir(): string {
22
+ return typeof import.meta.dir === "string"
23
+ ? import.meta.dir
24
+ : dirname(fileURLToPath(import.meta.url));
25
+ }
26
+
27
+ export function resolvePackageRoot(moduleDir: string = currentModuleDir()): string {
28
+ return resolve(moduleDir, "..");
29
+ }
30
+
31
+ function hasGitMetadata(startDir: string): boolean {
32
+ let currentDir = startDir;
33
+
34
+ while (true) {
35
+ if (existsSync(join(currentDir, ".git"))) return true;
36
+
37
+ const parentDir = dirname(currentDir);
38
+ if (parentDir === currentDir) return false;
39
+ currentDir = parentDir;
40
+ }
41
+ }
42
+
43
+ export function readVersion(packageRoot: string): string | null {
44
+ try {
45
+ const pkg = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf-8")) as {
46
+ version?: string;
47
+ };
48
+ return typeof pkg.version === "string" ? pkg.version : null;
49
+ } catch {
50
+ return null;
51
+ }
52
+ }
53
+
54
+ export function detectPhase({
55
+ env = process.env,
56
+ packageRoot = resolvePackageRoot(),
57
+ }: RuntimeInfoOptions = {}): AgentlogChannel {
58
+ const override = env.AGENTLOG_PHASE?.trim().toLowerCase();
59
+ if (override === "dev" || override === "prod") return override;
60
+ return hasGitMetadata(packageRoot) ? "dev" : "prod";
61
+ }
62
+
63
+ function readCommit(packageRoot: string, channel: AgentlogChannel): string | null {
64
+ if (channel !== "dev") return null;
65
+
66
+ const git = spawnSync("git", ["rev-parse", "--short", "HEAD"], {
67
+ cwd: packageRoot,
68
+ encoding: "utf-8",
69
+ timeout: 3000,
70
+ });
71
+
72
+ if (git.status !== 0) return null;
73
+ const commit = git.stdout.trim();
74
+ return commit.length > 0 ? commit : null;
75
+ }
76
+
77
+ export function getRuntimeInfo(options: RuntimeInfoOptions = {}): RuntimeInfo {
78
+ const env = options.env ?? process.env;
79
+ const packageRoot = options.packageRoot ?? resolvePackageRoot(options.moduleDir);
80
+ const gitBacked = hasGitMetadata(packageRoot);
81
+ const override = env.AGENTLOG_PHASE?.trim().toLowerCase();
82
+ const channel: AgentlogChannel =
83
+ override === "dev" || override === "prod" ? override : gitBacked ? "dev" : "prod";
84
+
85
+ return {
86
+ version: readVersion(packageRoot),
87
+ channel,
88
+ commit: channel === "dev" && gitBacked ? readCommit(packageRoot, channel) : null,
89
+ packageRoot,
90
+ };
91
+ }
92
+
93
+ export function formatVersionHeadline(info: Pick<RuntimeInfo, "version">): string {
94
+ return `AgentLog ${info.version ?? "unknown"}`;
95
+ }
96
+
97
+ export function formatVersionOutput(info: RuntimeInfo): string {
98
+ const lines = [formatVersionHeadline(info)];
99
+
100
+ if (info.channel === "dev") {
101
+ lines.push("channel: dev");
102
+ if (info.commit) lines.push(`commit: ${info.commit}`);
103
+ }
104
+
105
+ return lines.join("\n");
106
+ }