agent-optic 0.2.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 +21 -0
- package/README.md +337 -0
- package/examples/commit-tracker.ts +389 -0
- package/examples/cost-per-feature.ts +182 -0
- package/examples/match-git-commits.ts +171 -0
- package/examples/model-costs.ts +131 -0
- package/examples/pipe-match.ts +177 -0
- package/examples/prompt-history.ts +119 -0
- package/examples/session-digest.ts +89 -0
- package/examples/timesheet.ts +127 -0
- package/examples/work-patterns.ts +124 -0
- package/package.json +41 -0
- package/src/agent-optic.ts +325 -0
- package/src/aggregations/daily.ts +90 -0
- package/src/aggregations/project.ts +71 -0
- package/src/aggregations/time.ts +44 -0
- package/src/aggregations/tools.ts +60 -0
- package/src/claude-optic.ts +7 -0
- package/src/cli/index.ts +407 -0
- package/src/index.ts +69 -0
- package/src/parsers/content-blocks.ts +58 -0
- package/src/parsers/session-detail.ts +323 -0
- package/src/parsers/tool-categories.ts +86 -0
- package/src/pricing.ts +62 -0
- package/src/privacy/config.ts +67 -0
- package/src/privacy/redact.ts +99 -0
- package/src/readers/codex-rollout-reader.ts +145 -0
- package/src/readers/history-reader.ts +205 -0
- package/src/readers/plan-reader.ts +60 -0
- package/src/readers/project-reader.ts +101 -0
- package/src/readers/session-reader.ts +280 -0
- package/src/readers/skill-reader.ts +28 -0
- package/src/readers/stats-reader.ts +12 -0
- package/src/readers/task-reader.ts +117 -0
- package/src/types/aggregations.ts +47 -0
- package/src/types/plan.ts +6 -0
- package/src/types/privacy.ts +18 -0
- package/src/types/project.ts +13 -0
- package/src/types/provider.ts +9 -0
- package/src/types/session.ts +56 -0
- package/src/types/stats.ts +15 -0
- package/src/types/task.ts +16 -0
- package/src/types/transcript.ts +36 -0
- package/src/utils/dates.ts +40 -0
- package/src/utils/jsonl.ts +83 -0
- package/src/utils/paths.ts +57 -0
- package/src/utils/providers.ts +30 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kristoffer
|
|
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,337 @@
|
|
|
1
|
+
# agent-optic
|
|
2
|
+
|
|
3
|
+
> Reads local assistant history directories and returns structured JSON — sessions, costs, timesheets, work patterns.
|
|
4
|
+
|
|
5
|
+
Zero-dependency, local-first TypeScript library for reading session data from provider directories such as `~/.claude/`, `~/.codex/`, `~/.cursor/`, and `~/.windsurf/`.
|
|
6
|
+
|
|
7
|
+
> **Security Warning**: Provider home directories contain highly sensitive data — API keys, source code, credentials, and personal information may be present in plaintext session files. This library is designed with privacy as the primary concern. See [SECURITY.md](./SECURITY.md).
|
|
8
|
+
|
|
9
|
+
## Try it
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bunx agent-optic sessions
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- **Zero runtime dependencies**
|
|
18
|
+
- **No network access**
|
|
19
|
+
- **Privacy by default** — strips tool results and thinking blocks
|
|
20
|
+
- **Two-tier session loading** — fast (`history.jsonl`) or detailed (full parse)
|
|
21
|
+
- **Bun-native** — `Bun.file()`, `Bun.Glob`
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bun add agent-optic
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Examples
|
|
30
|
+
|
|
31
|
+
The `examples/` directory contains standalone scripts that show what your session data unlocks. Run any of them with `bun examples/<name>.ts`.
|
|
32
|
+
|
|
33
|
+
### Cost per Feature
|
|
34
|
+
|
|
35
|
+
Match sessions to git branches and calculate what each feature costs in tokens and USD.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
bun examples/cost-per-feature.ts --repo /path/to/repo
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
Cost per Feature / Branch
|
|
43
|
+
==========================================================================================
|
|
44
|
+
Feature/Branch Sessions Tokens Est. Cost Commits
|
|
45
|
+
------------------------------------------------------------------------------------------
|
|
46
|
+
feat/auth-system 8 2.3M $4.12 5
|
|
47
|
+
fix/memory-leak 3 890K $1.55 2
|
|
48
|
+
refactor/api-client 5 1.1M $2.08 3
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Match Git Commits
|
|
52
|
+
|
|
53
|
+
Correlate git commits with sessions by timestamp proximity — find which session produced each commit.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
bun examples/match-git-commits.ts --days 7
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Timesheet
|
|
60
|
+
|
|
61
|
+
Generate a weekly timesheet grouped by day and project, with gap-capped hours.
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
bun examples/timesheet.ts
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
Timesheet: 2026-02-10 → 2026-02-14
|
|
69
|
+
==========================================================================================
|
|
70
|
+
Day Date Project Hours Sessions Prompts
|
|
71
|
+
------------------------------------------------------------------------------------------
|
|
72
|
+
Mon 2026-02-10 claude-optic 2.3 4 18
|
|
73
|
+
my-app 1.1 2 8
|
|
74
|
+
Tue 2026-02-11 claude-optic 3.5 6 32
|
|
75
|
+
------------------------------------------------------------------------------------------
|
|
76
|
+
TOTAL 6.9 12 58
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Model Costs
|
|
80
|
+
|
|
81
|
+
Compare token usage and costs across model families.
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
bun examples/model-costs.ts
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
Model Usage & Costs: 2026-01-13 → 2026-02-12
|
|
89
|
+
====================================================================================================
|
|
90
|
+
Model Sessions Input Output Cache W Cache R Est. Cost
|
|
91
|
+
----------------------------------------------------------------------------------------------------
|
|
92
|
+
opus-4-5-20250514 12 4.2M 1.1M 3.8M 2.1M $98.42
|
|
93
|
+
sonnet-4-5-20250929 45 8.1M 2.3M 6.2M 4.5M $42.15
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Prompt History
|
|
97
|
+
|
|
98
|
+
Export sampled prompts grouped by project as JSON — pipe to an LLM for categorization or analysis.
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
bun examples/prompt-history.ts --from 2026-01-01 | claude "categorize these prompts by intent"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Session Digest
|
|
105
|
+
|
|
106
|
+
Compact session summaries as JSON — first prompt, branch, model, token counts, cost, duration.
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
bun examples/session-digest.ts --days 7 | claude "which sessions were the most productive?"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Work Patterns
|
|
113
|
+
|
|
114
|
+
Aggregated work pattern metrics as JSON — hour distribution, late-night/weekend counts, longest and most expensive sessions.
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
bun examples/work-patterns.ts | claude "analyze my work patterns and suggest improvements"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Commit Tracker
|
|
121
|
+
|
|
122
|
+
Post-commit hook that records AI usage per commit to `.ai-usage.jsonl`.
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Install the git hook
|
|
126
|
+
bun examples/commit-tracker.ts install
|
|
127
|
+
|
|
128
|
+
# Or run manually for the latest commit
|
|
129
|
+
bun examples/commit-tracker.ts run
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Each commit gets a JSONL record with matched sessions, token counts, and cost:
|
|
133
|
+
|
|
134
|
+
```json
|
|
135
|
+
{"commit":"7c5a457","timestamp":"2026-02-13T21:12:13.000Z","branch":"main","sessions":2,"tokens":{"input":194,"output":1638,"cache_read":1534390,"cache_write":83203},"cost_usd":1.33,"models":["claude-opus-4-6"],"messages":89,"files_changed":2}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# Uninstall when done
|
|
140
|
+
bun examples/commit-tracker.ts uninstall
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Pipe Match
|
|
144
|
+
|
|
145
|
+
Generic stdin matcher — pipe in any JSON with timestamps, match against sessions.
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
# Match GitHub PRs to sessions that produced them
|
|
149
|
+
gh pr list --json createdAt,title | bun examples/pipe-match.ts --field createdAt
|
|
150
|
+
|
|
151
|
+
# Match GitHub issues
|
|
152
|
+
gh issue list --json createdAt,title | bun examples/pipe-match.ts --field createdAt
|
|
153
|
+
|
|
154
|
+
# Match any timestamped JSON
|
|
155
|
+
echo '[{"timestamp":"2026-02-10T14:00:00Z","title":"Deploy v2.1"}]' | bun examples/pipe-match.ts
|
|
156
|
+
|
|
157
|
+
# Works with any JSON — work items, calendar events, deploys, etc.
|
|
158
|
+
cat events.json | bun examples/pipe-match.ts
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Quick Start
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
import { createHistory } from "agent-optic";
|
|
165
|
+
|
|
166
|
+
const ch = createHistory({ provider: "claude" });
|
|
167
|
+
|
|
168
|
+
// List today's sessions (fast — reads only history.jsonl)
|
|
169
|
+
const sessions = await ch.sessions.list();
|
|
170
|
+
|
|
171
|
+
// List with metadata (slower — peeks session files for branch/model/tokens)
|
|
172
|
+
const withMeta = await ch.sessions.listWithMeta();
|
|
173
|
+
|
|
174
|
+
// Get full session detail
|
|
175
|
+
const detail = await ch.sessions.detail(sessionId, projectPath);
|
|
176
|
+
|
|
177
|
+
// Stream transcript entries
|
|
178
|
+
for await (const entry of ch.sessions.transcript(sessionId, projectPath)) {
|
|
179
|
+
console.log(entry.message?.role, entry.timestamp);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Daily summary (sessions + tasks + plans + todos + project memory)
|
|
183
|
+
const daily = await ch.aggregate.daily("2026-02-09");
|
|
184
|
+
|
|
185
|
+
// Project summaries
|
|
186
|
+
const projects = await ch.aggregate.byProject({ from: "2026-02-01", to: "2026-02-09" });
|
|
187
|
+
|
|
188
|
+
// Estimate cost of a session
|
|
189
|
+
import { estimateCost } from "agent-optic";
|
|
190
|
+
const cost = estimateCost(withMeta[0]); // USD
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## API
|
|
194
|
+
|
|
195
|
+
### `createHistory(config?)`
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
const ch = createHistory({
|
|
199
|
+
provider: "claude", // "claude" | "codex" | "openai" | "cursor" | "windsurf"
|
|
200
|
+
providerDir: "~/.claude", // default: provider-specific home directory
|
|
201
|
+
privacy: "local", // "local" | "shareable" | "strict" | Partial<PrivacyConfig>
|
|
202
|
+
cache: true, // default: true
|
|
203
|
+
});
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
`openai` is currently an alias of Codex-format local history and defaults to `~/.codex`.
|
|
207
|
+
|
|
208
|
+
`createClaudeHistory()` is still exported for backward compatibility and behaves like `createHistory({ provider: "claude" })`.
|
|
209
|
+
|
|
210
|
+
### Sessions
|
|
211
|
+
|
|
212
|
+
| Method | Speed | Reads | Returns |
|
|
213
|
+
|--------|-------|-------|---------|
|
|
214
|
+
| `sessions.list(filter?)` | Fast | `history.jsonl` only | `SessionInfo[]` |
|
|
215
|
+
| `sessions.listWithMeta(filter?)` | Medium | + peeks session files | `SessionMeta[]` |
|
|
216
|
+
| `sessions.detail(id, project)` | Slow | Full session parse | `SessionDetail` |
|
|
217
|
+
| `sessions.transcript(id, project)` | Streaming | Full session file | `AsyncGenerator<TranscriptEntry>` |
|
|
218
|
+
| `sessions.count(filter?)` | Fast | `history.jsonl` only | `number` |
|
|
219
|
+
|
|
220
|
+
### Other Data
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
ch.projects.list() // ProjectInfo[]
|
|
224
|
+
ch.projects.memory(projectPath) // ProjectMemory | null
|
|
225
|
+
ch.tasks.list({ date: "2026-02-09" }) // TaskInfo[]
|
|
226
|
+
ch.todos.list({ date: "2026-02-09" }) // TodoItem[]
|
|
227
|
+
ch.plans.list({ date: "2026-02-09" }) // PlanInfo[]
|
|
228
|
+
ch.skills.list() // string[]
|
|
229
|
+
ch.skills.read("skill-name") // string (SKILL.md content)
|
|
230
|
+
ch.stats.get() // StatsCache | null
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Aggregations
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
ch.aggregate.daily("2026-02-09") // DailySummary
|
|
237
|
+
ch.aggregate.dailyRange("2026-02-01", "2026-02-09") // DailySummary[]
|
|
238
|
+
ch.aggregate.byProject({ from: "2026-02-01" }) // ProjectSummary[]
|
|
239
|
+
ch.aggregate.toolUsage({ date: "2026-02-09" }) // ToolUsageReport
|
|
240
|
+
ch.aggregate.estimateHours(sessions) // number (gap-capped)
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Cost Estimation
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
import { estimateCost, getModelPricing, MODEL_PRICING } from "agent-optic";
|
|
247
|
+
|
|
248
|
+
// Estimate cost for a session (requires SessionMeta — use listWithMeta)
|
|
249
|
+
const session = (await ch.sessions.listWithMeta())[0];
|
|
250
|
+
const cost = estimateCost(session); // USD
|
|
251
|
+
|
|
252
|
+
// Look up pricing for a model
|
|
253
|
+
const pricing = getModelPricing("claude-opus-4-6");
|
|
254
|
+
// { input: 5, output: 25, cacheWrite: 6.25, cacheRead: 0.5 } per million tokens
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Filters
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
// Date filter (all methods)
|
|
261
|
+
{ date: "2026-02-09" } // Single day
|
|
262
|
+
{ from: "2026-02-01", to: "2026-02-09" } // Range
|
|
263
|
+
{ from: "2026-02-01" } // From date to today
|
|
264
|
+
|
|
265
|
+
// Session filter (extends DateFilter)
|
|
266
|
+
{ date: "2026-02-09", project: "my-app" } // Filter by project name
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Privacy Profiles
|
|
270
|
+
|
|
271
|
+
| Profile | Strips |
|
|
272
|
+
|---------|--------|
|
|
273
|
+
| `local` (default) | Tool results, thinking blocks |
|
|
274
|
+
| `shareable` | + absolute paths, home directory |
|
|
275
|
+
| `strict` | + prompt text, emails, credential patterns, IPs |
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
// Use a built-in profile
|
|
279
|
+
const ch = createHistory({ provider: "claude", privacy: "strict" });
|
|
280
|
+
|
|
281
|
+
// Or customize
|
|
282
|
+
const ch = createHistory({
|
|
283
|
+
provider: "claude",
|
|
284
|
+
privacy: {
|
|
285
|
+
redactPrompts: false,
|
|
286
|
+
stripToolResults: true,
|
|
287
|
+
stripThinking: true,
|
|
288
|
+
excludeProjects: ["/work/secret-project"],
|
|
289
|
+
},
|
|
290
|
+
});
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## CLI
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
# Agent-friendly list (JSONL stream)
|
|
297
|
+
bunx agent-optic sessions --provider codex --format jsonl
|
|
298
|
+
|
|
299
|
+
# Detail for one session
|
|
300
|
+
bunx agent-optic detail 019c9aea-484d-7200-87fd-07a545276ac4 --provider openai
|
|
301
|
+
|
|
302
|
+
# Transcript stream (limit + selected fields)
|
|
303
|
+
bunx agent-optic transcript 019c9aea-484d-7200-87fd-07a545276ac4 --provider openai --format jsonl --limit 50 --fields timestamp,message
|
|
304
|
+
|
|
305
|
+
# Tool usage report
|
|
306
|
+
bunx agent-optic tool-usage --provider codex --from 2026-02-01 --to 2026-02-26
|
|
307
|
+
|
|
308
|
+
# Daily summary
|
|
309
|
+
bunx agent-optic daily --date 2026-02-09
|
|
310
|
+
|
|
311
|
+
# Raw output without envelope
|
|
312
|
+
bunx agent-optic sessions --provider claude --date 2026-02-09 --raw
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
`--format json` returns a stable envelope (`schemaVersion`, `command`, `provider`, `generatedAt`, `data`) by default.
|
|
316
|
+
Use `--raw` for data-only output and `--format jsonl` for one JSON object per line.
|
|
317
|
+
|
|
318
|
+
## Architecture
|
|
319
|
+
|
|
320
|
+
```
|
|
321
|
+
src/
|
|
322
|
+
agent-optic.ts # Main factory: createHistory()
|
|
323
|
+
claude-optic.ts # Backward-compatible Claude aliases
|
|
324
|
+
pricing.ts # Model pricing data and cost estimation
|
|
325
|
+
types/ # Type definitions (one file per domain)
|
|
326
|
+
readers/ # File readers (history, session, tasks, plans, projects, stats)
|
|
327
|
+
parsers/ # Session parsing, tool categorization, content extraction
|
|
328
|
+
aggregations/ # Daily/project/tool summaries, time estimation
|
|
329
|
+
privacy/ # Redaction engine, privacy profiles
|
|
330
|
+
utils/ # Dates, paths, JSONL streaming
|
|
331
|
+
cli/ # CLI entry point
|
|
332
|
+
examples/ # Standalone scripts showing what the data unlocks
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## License
|
|
336
|
+
|
|
337
|
+
MIT
|