granola-toolkit 0.34.0 → 0.34.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.
Files changed (2) hide show
  1. package/README.md +22 -425
  2. package/package.json +7 -1
package/README.md CHANGED
@@ -1,11 +1,9 @@
1
1
  # granola-toolkit
2
2
 
3
- Toolkit for working with Granola meetings, notes, and transcripts.
3
+ Toolkit for working with Granola meetings, notes, transcripts, folders, and local workspaces.
4
4
 
5
5
  ## Install
6
6
 
7
- From npm:
8
-
9
7
  ```bash
10
8
  npm install -g granola-toolkit
11
9
  granola --help
@@ -15,449 +13,48 @@ Without a global install:
15
13
 
16
14
  ```bash
17
15
  npx granola-toolkit --help
18
- npx granola-toolkit meeting --help
19
- ```
20
-
21
- For local development:
22
-
23
- ```bash
24
- curl -fsSL https://vite.plus | bash
25
- vp help
26
- vp install
27
- ```
28
-
29
- ## Run
30
-
31
- Installed command:
32
-
33
- ```bash
34
- granola --help
35
- granola attach --help
36
- granola auth login
37
- granola exports --help
38
- granola folder --help
39
- granola meeting --help
40
- granola notes --help
41
- granola serve --help
42
- granola tui --help
43
- granola transcripts --help
44
- granola web --help
45
16
  ```
46
17
 
47
18
  The published package exposes both `granola` and `granola-toolkit` as executable names.
48
19
 
49
- Local build:
50
-
51
- ```bash
52
- vp pack
53
- node dist/cli.js --help
54
- node dist/cli.js attach --help
55
- node dist/cli.js exports --help
56
- node dist/cli.js folder --help
57
- node dist/cli.js meeting --help
58
- node dist/cli.js notes --help
59
- node dist/cli.js serve --help
60
- node dist/cli.js tui --help
61
- node dist/cli.js transcripts --help
62
- node dist/cli.js web --help
63
- ```
64
-
65
- You can also use the package scripts:
66
-
67
- ```bash
68
- npm run build
69
- npm run start -- meeting --help
70
- npm run notes -- --help
71
- npm run tui -- --help
72
- npm run transcripts -- --help
73
- ```
74
-
75
- ## Examples
76
-
77
- Export notes:
20
+ ## Quick Start
78
21
 
79
22
  ```bash
80
23
  granola auth login
81
- granola notes
82
- granola notes --folder Team
83
-
84
- node dist/cli.js notes --supabase "$HOME/Library/Application Support/Granola/supabase.json"
85
- node dist/cli.js notes --format json --output ./notes-json
86
- granola exports list
87
- granola exports rerun notes-1234abcd
88
- ```
89
-
90
- Export transcripts:
91
-
92
- ```bash
93
- node dist/cli.js transcripts --cache "$HOME/Library/Application Support/Granola/cache-v3.json"
94
- node dist/cli.js transcripts --format yaml --output ./transcripts-yaml
95
- granola transcripts --folder Team
96
- ```
97
-
98
- Inspect individual meetings:
99
-
100
- ```bash
101
24
  granola folder list
102
- granola folder view Team
103
25
  granola meeting list --limit 10
104
- granola meeting list --search planning
105
- granola meeting list --folder Team
106
- granola meeting view 1234abcd
107
- granola meeting notes 1234abcd
108
- granola meeting transcript 1234abcd --format json
109
- granola meeting export 1234abcd --format yaml
110
- granola meeting open 1234abcd
111
- granola tui
112
- granola tui --meeting 1234abcd
113
- ```
114
-
115
- Run the local API server:
116
-
117
- ```bash
118
- granola serve
119
- granola serve --port 4096
120
- granola serve --hostname 0.0.0.0 --port 4096
121
- granola serve --network lan --password "change-me"
122
- granola attach http://127.0.0.1:4096
123
- granola attach http://127.0.0.1:4096 --meeting 1234abcd
124
- granola attach http://127.0.0.1:4096 --password "change-me"
125
-
26
+ granola notes --folder Team
126
27
  granola web
127
- granola web --meeting 1234abcd
128
- granola web --open=false --port 4096
129
- granola web --network lan --password "change-me" --trusted-origins "https://trusted.example"
28
+ granola tui
130
29
  ```
131
30
 
132
- ## How It Works
133
-
134
- ### Notes
135
-
136
- `notes` exports Granola's generated meeting notes, not the raw transcript.
137
-
138
- The flow is:
139
-
140
- 1. read a stored Granola session, or fall back to your local `supabase.json`
141
- 2. extract the WorkOS access token from it
142
- 3. call Granola's paginated documents API
143
- 4. normalise each document into a structured note export
144
- 5. choose the best available note content for each document
145
- 6. render that export as Markdown, JSON, YAML, or raw JSON
146
- 7. write one file per document into the output directory
147
-
148
- When you pass `--folder <id|name>`, the export is filtered to that folder and, by default, written into a stable per-folder subdirectory under the notes output root.
149
-
150
- Content is chosen in this order:
151
-
152
- 1. `notes`
153
- 2. `last_viewed_panel.content`
154
- 3. `last_viewed_panel.original_content`
155
- 4. raw `content`
156
-
157
- Markdown note files include:
158
-
159
- - YAML frontmatter with the document id, created timestamp, updated timestamp, and tags
160
- - a top-level heading from the note title
161
- - converted note body content
162
-
163
- ### Transcripts
164
-
165
- `transcripts` exports Granola's locally cached transcript segments.
166
-
167
- The flow is:
168
-
169
- 1. read Granola's cache JSON from disk
170
- 2. parse the cache payload, whether it is double-encoded or already an object
171
- 3. normalise transcript data into a structured export per document
172
- 4. match transcript segments to documents by document id
173
- 5. render each export as text, JSON, YAML, or raw JSON
174
- 6. write one file per document into the output directory
175
-
176
- When you pass `--folder <id|name>`, the export is filtered to that folder and, by default, written into a stable per-folder subdirectory under the transcripts output root.
177
-
178
- Speaker labels are currently normalised to:
179
-
180
- - `You` for `microphone`
181
- - `System` for everything else
182
-
183
- Structured output formats are useful when you want to post-process exports in scripts instead of reading the default human-oriented Markdown or text files.
184
-
185
- ### Meetings
186
-
187
- `meeting` combines the API-backed notes path with the local transcript cache so you can inspect one meeting at a time.
188
-
189
- The flow is:
190
-
191
- 1. read a stored Granola session, or fall back to `supabase.json`
192
- 2. fetch documents from Granola's API
193
- 3. optionally load the local cache for transcript data
194
- 4. resolve a meeting by full id or unique id prefix
195
- 5. render either a list, a combined meeting view, focused notes/transcript output, or a machine-readable export bundle
196
-
197
- The human-readable `view` command shows:
198
-
199
- - meeting metadata
200
- - the selected notes content
201
- - transcript lines when the local cache is available
202
-
203
- The focused meeting subcommands are:
204
-
205
- - `meeting notes` for just the selected note output
206
- - `meeting transcript` for just the selected transcript output
207
- - `meeting open` to start the web workspace focused on one meeting
208
-
209
- The machine-readable `export` command includes:
31
+ ## Documentation
210
32
 
211
- - a meeting summary
212
- - structured note data plus rendered Markdown
213
- - structured transcript data plus rendered transcript text when available
33
+ The detailed documentation now lives in the dedicated docs app under
34
+ [`docs/`](https://github.com/kkarimi/granola-toolkit/tree/main/docs).
214
35
 
215
- ### Folders
216
-
217
- `folder` exposes Granola document lists as a first-class concept instead of leaving meetings in one flat global list.
218
-
219
- The flow is:
220
-
221
- 1. reuse the shared auth path that `notes` and `meeting` already use
222
- 2. call Granola's document-list API, with `v2` first and `v1` fallback
223
- 3. normalise folder metadata and document membership into shared folder records
224
- 4. attach folder membership to meetings in the shared app core
225
- 5. let folder commands and meeting filters resolve folders by id, prefix, or unique name
226
-
227
- The current CLI surface includes:
228
-
229
- - `folder list`
230
- - `folder view <id|name>`
231
- - `meeting list --folder <id|name>`
232
- - `notes --folder <id|name>`
233
- - `transcripts --folder <id|name>`
234
-
235
- ### Server
236
-
237
- `serve` starts a long-lived local `Granola Toolkit` server on one shared app instance.
238
-
239
- The initial server API includes:
240
-
241
- - `GET /health`
242
- - `GET /server/info`
243
- - `POST /auth/unlock` for password-protected servers
244
- - `POST /auth/lock` to clear the browser/API unlock cookie
245
- - `GET /auth/status`
246
- - `GET /state`
247
- - `GET /events` for server-sent state updates
248
- - `GET /folders`
249
- - `GET /folders/resolve?q=<query>`
250
- - `GET /folders/:id`
251
- - `GET /meetings`
252
- - `GET /meetings?folderId=<id>` for folder-scoped meeting lists
253
- - `GET /meetings?refresh=true` to bypass the local meeting index and force a live refresh
254
- - `GET /meetings/resolve?q=<query>`
255
- - `GET /meetings/:id`
256
- - `GET /exports/jobs`
257
- - `POST /auth/login`
258
- - `POST /auth/logout`
259
- - `POST /auth/mode`
260
- - `POST /auth/refresh`
261
- - `POST /exports/notes` with optional `folderId`
262
- - `POST /exports/jobs/:id/rerun`
263
- - `POST /exports/transcripts` with optional `folderId`
264
-
265
- This is the shared runtime for `granola web` and `granola attach`.
266
-
267
- Server hardening now includes:
268
-
269
- - `local` network mode by default, which binds to `127.0.0.1`
270
- - `lan` network mode when you explicitly want other devices to connect
271
- - optional password protection for API routes and the browser client
272
- - trusted-origin checks for browser requests, with CORS headers only for allowed origins
273
- - a warning when you expose the server on `lan` without a password
274
-
275
- ### Web
276
-
277
- `web` starts the same local server as `serve`, enables the browser client at `/`, and opens that workspace in your default browser unless you pass `--open=false`.
278
-
279
- You can deep-link into a specific meeting with either:
280
-
281
- - `granola web --meeting <id>`
282
- - `granola meeting open <id>`
283
-
284
- The initial browser client includes:
285
-
286
- - a dedicated folder pane with an explicit All meetings scope
287
- - a searchable meeting list
288
- - folder-aware meeting browsing with one-click scope changes
289
- - a fast local-index warm start for meeting browsing before live documents finish loading
290
- - sort and updated-date filters
291
- - quick open by meeting id or title
292
- - browser URL state that preserves the selected folder, meeting, and tab
293
- - a focused meeting workspace with notes, transcript, metadata, and raw tabs
294
- - keyboard-first workspace switching with `1`-`4`, `[` and `]`
295
- - app-state status from the shared core
296
- - an auth session panel for login, refresh, source switching, and sign-out
297
- - note and transcript export actions backed by the same local API
298
- - folder-scoped export actions that follow the currently selected folder
299
- - a recent export-jobs panel with rerun actions
300
- - stronger empty and error states for list/detail failures
301
- - a server-access panel that can unlock or lock a password-protected local server
302
-
303
- ### Attach
304
-
305
- `attach` connects the terminal workspace to an already running `granola serve` or `granola web` instance instead of starting a second isolated app.
306
-
307
- Use it when you want:
308
-
309
- - two terminal workspaces attached to the same live app state
310
- - one terminal workspace and one browser workspace sharing auth, meeting index, and export-job history
311
- - a password-protected local server to remain the single source of truth
312
-
313
- The attach flow uses the existing local HTTP API plus `GET /events` for live state updates.
314
-
315
- ### Runtime Boundaries
316
-
317
- The toolkit now keeps its local persistence and transport contracts explicit:
318
-
319
- - one shared local data directory for export jobs, meeting index data, and any file-backed session state
320
- - one versioned local HTTP transport contract, exposed by `GET /server/info`
321
- - one remote client handshake that validates the transport protocol before attaching
322
-
323
- That keeps the current single-package repo simple, while making a future split into separate server/client packages or remote-hosted clients much less invasive.
324
-
325
- ### TUI
326
-
327
- `tui` starts a full-screen terminal workspace on the shared app core, without requiring the local server or browser client. Use `attach` when you want the same workspace against an existing shared server instance instead.
328
-
329
- The initial terminal workspace includes:
330
-
331
- - a folder scope inside the navigation pane, including an explicit All meetings view
332
- - a meeting list pane with keyboard navigation
333
- - a detail pane with notes, transcript, metadata, and raw views
334
- - an auth session overlay for import, refresh, source switching, and sign-out
335
- - a footer with app state and key hints
336
- - a quick-open overlay for jumping by title, id, or tag
337
-
338
- The main keyboard controls are:
339
-
340
- - `h` / `l`, left / right, or `Tab` to switch between folders and meetings
341
- - `j` / `k` or arrow keys to move within the active folder or meeting list
342
- - `/` or `Ctrl+P` to open quick open
343
- - `a` to open auth session actions
344
- - `1`-`4` to switch detail tabs
345
- - `PageUp` / `PageDown` to scroll the detail pane
346
- - `r` to refresh from live Granola data
347
- - `q` to quit
348
-
349
- ### Local Meeting Index
350
-
351
- Interactive meeting browsing now keeps a local index of meeting summaries and metadata.
352
-
353
- That index is used to:
354
-
355
- - make the web meeting list available quickly on startup
356
- - keep search, sort, and date filtering useful before every live document payload is fetched again
357
- - refresh itself after successful live loads so the next run starts warm
358
-
359
- The web client uses the index as a fast path and upgrades to live data automatically when the background refresh completes. The manual Refresh button bypasses the index and forces a live meeting fetch immediately.
360
-
361
- ### Export Jobs
362
-
363
- Exports are now tracked as jobs with:
364
-
365
- - persistent local history across CLI and web runs
366
- - explicit scope metadata for all-meetings and folder-scoped runs
367
- - running, completed, and failed status
368
- - per-export progress counters
369
- - rerun support from `granola exports rerun <job-id>` or the web client
370
-
371
- Use `granola exports list` to inspect recent jobs from the CLI.
372
-
373
- ## Auth
374
-
375
- If you do not want to keep passing `--supabase`, import the desktop app session once:
36
+ Local docs development:
376
37
 
377
38
  ```bash
378
- granola auth login
379
- granola auth status
380
- granola auth refresh
381
- granola auth use stored
382
- granola auth use supabase
383
- ```
384
-
385
- That stores a reusable Granola session locally and lets `granola notes` use it directly.
386
-
387
- `granola auth` now supports:
388
-
389
- - `login` to import the desktop app session into the toolkit store
390
- - `status` to inspect the active source, stored-session availability, refresh support, and any last auth error
391
- - `refresh` to refresh the stored session explicitly
392
- - `use stored` or `use supabase` to switch the active auth source
393
- - `logout` to delete the stored session
394
-
395
- The same auth actions are also available from the web workspace.
396
-
397
- ### Incremental Writes
398
-
399
- Both commands keep a small hidden state file in the output directory to track:
400
-
401
- - document id to filename
402
- - content hash
403
- - source timestamp
404
- - last export time
405
-
406
- That state is used to:
407
-
408
- - keep filenames stable even if a meeting title changes later
409
- - skip rewrites when the rendered content is unchanged
410
- - migrate old files cleanly when the output format changes
411
- - delete stale exports when a document disappears from the source data
412
-
413
- That makes repeated runs cheap and keeps long-lived export directories much cleaner.
414
-
415
- ## Config
416
-
417
- The CLI reads configuration in this order:
418
-
419
- 1. command-line flags
420
- 2. environment variables
421
- 3. `.granola.toml`
422
- 4. platform defaults
423
-
424
- Supported config keys:
425
-
426
- ```toml
427
- debug = true
428
- supabase = "/Users/yourname/Library/Application Support/Granola/supabase.json"
429
- output = "./notes"
430
- timeout = "2m"
431
- cache-file = "/Users/yourname/Library/Application Support/Granola/cache-v3.json"
432
- transcript-output = "./transcripts"
39
+ npm run docs:dev
40
+ npm run docs:check
433
41
  ```
434
42
 
435
- Supported environment variables:
436
-
437
- - `DEBUG_MODE`
438
- - `SUPABASE_FILE`
439
- - `OUTPUT`
440
- - `TIMEOUT`
441
- - `CACHE_FILE`
442
- - `TRANSCRIPT_OUTPUT`
443
- - `GRANOLA_CLIENT_VERSION`
43
+ Key docs entry points:
444
44
 
445
- ## Development Checks
45
+ - [`Overview`](https://github.com/kkarimi/granola-toolkit/blob/main/docs/content/docs/index.mdx)
46
+ - [`Getting Started`](https://github.com/kkarimi/granola-toolkit/blob/main/docs/content/docs/getting-started.mdx)
47
+ - [`Exporting`](https://github.com/kkarimi/granola-toolkit/blob/main/docs/content/docs/exporting.mdx)
48
+ - [`Meetings and Folders`](https://github.com/kkarimi/granola-toolkit/blob/main/docs/content/docs/meetings-and-folders.mdx)
49
+ - [`Server, Web, and TUI`](https://github.com/kkarimi/granola-toolkit/blob/main/docs/content/docs/server-web-and-tui.mdx)
50
+ - [`Auth and Configuration`](https://github.com/kkarimi/granola-toolkit/blob/main/docs/content/docs/auth-and-configuration.mdx)
51
+ - [`Development`](https://github.com/kkarimi/granola-toolkit/blob/main/docs/content/docs/development.mdx)
446
52
 
447
- Before pushing changes, run:
53
+ ## Local Development
448
54
 
449
55
  ```bash
450
- vp check
451
- vp test
56
+ curl -fsSL https://vite.plus | bash
57
+ vp install
452
58
  vp pack
453
- npm pack --dry-run
59
+ node dist/cli.js --help
454
60
  ```
455
-
456
- What those do:
457
-
458
- - `vp check`: formatting, linting, and type checks
459
- - `vp test`: unit tests
460
- - `vp pack`: builds the CLI bundle into `dist/cli.js`
461
- - `npm pack --dry-run`: shows the exact npm package contents without publishing
462
-
463
- `vp build` is for web apps. This repo is a CLI package, so the build step here is `vp pack`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "granola-toolkit",
3
- "version": "0.34.0",
3
+ "version": "0.34.2",
4
4
  "description": "Toolkit for exporting and working with Granola meetings, notes, and transcripts",
5
5
  "keywords": [
6
6
  "cli",
@@ -34,7 +34,12 @@
34
34
  "scripts": {
35
35
  "build": "vp pack",
36
36
  "check": "vp check",
37
+ "coverage": "vp test --coverage",
37
38
  "dev": "vp pack --watch",
39
+ "docs:build": "npm --prefix docs run build",
40
+ "docs:check": "npm --prefix docs run types:check && npm --prefix docs run build",
41
+ "docs:dev": "npm --prefix docs run dev",
42
+ "docs:start": "npm --prefix docs run start",
38
43
  "fmt": "vp fmt",
39
44
  "lint": "vp lint",
40
45
  "pack:dry-run": "npm pack --dry-run",
@@ -57,6 +62,7 @@
57
62
  },
58
63
  "devDependencies": {
59
64
  "@types/node": "^25.5.2",
65
+ "@vitest/coverage-v8": "4.1.2",
60
66
  "typescript": "^5.9.3",
61
67
  "vite-plus": "0.1.15"
62
68
  },