granola-toolkit 0.1.0 → 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/README.md +8 -59
- package/dist/cli.js +170 -153
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -146,17 +146,9 @@ Supported environment variables:
|
|
|
146
146
|
- `CACHE_FILE`
|
|
147
147
|
- `TRANSCRIPT_OUTPUT`
|
|
148
148
|
|
|
149
|
-
##
|
|
149
|
+
## Development Checks
|
|
150
150
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
- deterministic export ordering, so duplicate-title suffixes are stable across runs
|
|
154
|
-
- shared filename sanitisation between notes and transcripts
|
|
155
|
-
- cross-platform default path discovery for both `supabase.json` and cache files
|
|
156
|
-
- HTML fallback for note export is converted into readable Markdown-ish text instead of being dumped raw
|
|
157
|
-
- transcript timestamps preserve the original clock time instead of being normalised to UTC
|
|
158
|
-
|
|
159
|
-
## Verify
|
|
151
|
+
Before pushing changes, run:
|
|
160
152
|
|
|
161
153
|
```bash
|
|
162
154
|
vp check
|
|
@@ -165,54 +157,11 @@ vp pack
|
|
|
165
157
|
npm pack --dry-run
|
|
166
158
|
```
|
|
167
159
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
## Publishing
|
|
171
|
-
|
|
172
|
-
Any push to `main` with a package version that is not already on npm becomes a publish candidate automatically. The workflow verifies the build, checks whether `package.json` contains an unpublished version, and then pauses in the `production` environment until someone approves the deployment review in GitHub.
|
|
173
|
-
|
|
174
|
-
That means you can use either flow:
|
|
175
|
-
|
|
176
|
-
- merge a PR that already includes the version bump
|
|
177
|
-
- run the local release helper on `main`
|
|
178
|
-
|
|
179
|
-
Local release helper:
|
|
180
|
-
|
|
181
|
-
```bash
|
|
182
|
-
npm run release
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
That script:
|
|
186
|
-
|
|
187
|
-
1. verifies the git working tree is clean
|
|
188
|
-
2. verifies you are on `main`
|
|
189
|
-
3. bumps the package version with `npm version --no-git-tag-version`
|
|
190
|
-
4. commits and pushes the release commit
|
|
191
|
-
5. lets the push-to-`main` workflow create a publish candidate automatically
|
|
192
|
-
|
|
193
|
-
You can also choose the bump type explicitly:
|
|
194
|
-
|
|
195
|
-
```bash
|
|
196
|
-
npm run release patch
|
|
197
|
-
npm run release minor
|
|
198
|
-
npm run release major
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
The GitHub Actions release job then:
|
|
202
|
-
|
|
203
|
-
- installs dependencies with Vite+ via `setup-vp`
|
|
204
|
-
- runs `vp check`, `vp test`, `vp pack`, and `npm pack --dry-run`
|
|
205
|
-
- checks npm first and skips the publish job if that exact version already exists
|
|
206
|
-
- waits for approval on the `production` environment before npm credentials are exposed
|
|
207
|
-
- publishes to npm using `NPM_TOKEN`
|
|
208
|
-
- tags the published version as `v<version>`
|
|
209
|
-
|
|
210
|
-
### GitHub Setup
|
|
211
|
-
|
|
212
|
-
To get the review dialog you showed in the screenshots, configure this once in GitHub:
|
|
160
|
+
What those do:
|
|
213
161
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
162
|
+
- `vp check`: formatting, linting, and type checks
|
|
163
|
+
- `vp test`: unit tests
|
|
164
|
+
- `vp pack`: builds the CLI bundle into `dist/cli.js`
|
|
165
|
+
- `npm pack --dry-run`: shows the exact npm package contents without publishing
|
|
217
166
|
|
|
218
|
-
|
|
167
|
+
`vp build` is for web apps. This repo is a CLI package, so the build step here is `vp pack`.
|
package/dist/cli.js
CHANGED
|
@@ -274,60 +274,6 @@ async function fetchDocuments(options) {
|
|
|
274
274
|
return documents;
|
|
275
275
|
}
|
|
276
276
|
//#endregion
|
|
277
|
-
//#region src/cache.ts
|
|
278
|
-
function parseCacheDocument(id, value) {
|
|
279
|
-
const record = asRecord(value);
|
|
280
|
-
if (!record) return;
|
|
281
|
-
return {
|
|
282
|
-
createdAt: stringValue(record.created_at),
|
|
283
|
-
id,
|
|
284
|
-
title: stringValue(record.title),
|
|
285
|
-
updatedAt: stringValue(record.updated_at)
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
function parseTranscriptSegments(value) {
|
|
289
|
-
if (!Array.isArray(value)) return;
|
|
290
|
-
return value.flatMap((segment) => {
|
|
291
|
-
const record = asRecord(segment);
|
|
292
|
-
if (!record) return [];
|
|
293
|
-
return [{
|
|
294
|
-
documentId: stringValue(record.document_id),
|
|
295
|
-
endTimestamp: stringValue(record.end_timestamp),
|
|
296
|
-
id: stringValue(record.id),
|
|
297
|
-
isFinal: Boolean(record.is_final),
|
|
298
|
-
source: stringValue(record.source),
|
|
299
|
-
startTimestamp: stringValue(record.start_timestamp),
|
|
300
|
-
text: stringValue(record.text)
|
|
301
|
-
}];
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
function parseCacheContents(contents) {
|
|
305
|
-
const outer = parseJsonString(contents);
|
|
306
|
-
if (!outer) throw new Error("failed to parse cache JSON");
|
|
307
|
-
const rawCache = outer.cache;
|
|
308
|
-
let cachePayload;
|
|
309
|
-
if (typeof rawCache === "string") cachePayload = parseJsonString(rawCache);
|
|
310
|
-
else cachePayload = asRecord(rawCache);
|
|
311
|
-
const state = cachePayload ? asRecord(cachePayload.state) : void 0;
|
|
312
|
-
if (!state) throw new Error("failed to parse cache state");
|
|
313
|
-
const rawDocuments = asRecord(state.documents) ?? {};
|
|
314
|
-
const rawTranscripts = asRecord(state.transcripts) ?? {};
|
|
315
|
-
const documents = {};
|
|
316
|
-
for (const [id, rawDocument] of Object.entries(rawDocuments)) {
|
|
317
|
-
const document = parseCacheDocument(id, rawDocument);
|
|
318
|
-
if (document) documents[id] = document;
|
|
319
|
-
}
|
|
320
|
-
const transcripts = {};
|
|
321
|
-
for (const [id, rawTranscript] of Object.entries(rawTranscripts)) {
|
|
322
|
-
const segments = parseTranscriptSegments(rawTranscript);
|
|
323
|
-
if (segments) transcripts[id] = segments;
|
|
324
|
-
}
|
|
325
|
-
return {
|
|
326
|
-
documents,
|
|
327
|
-
transcripts
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
//#endregion
|
|
331
277
|
//#region src/config.ts
|
|
332
278
|
function pickString(value) {
|
|
333
279
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
@@ -529,6 +475,113 @@ async function writeNotes(documents, outputDir) {
|
|
|
529
475
|
return written;
|
|
530
476
|
}
|
|
531
477
|
//#endregion
|
|
478
|
+
//#region src/commands/shared.ts
|
|
479
|
+
function debug(enabled, ...values) {
|
|
480
|
+
if (enabled) console.error("[debug]", ...values);
|
|
481
|
+
}
|
|
482
|
+
//#endregion
|
|
483
|
+
//#region src/commands/notes.ts
|
|
484
|
+
function notesHelp() {
|
|
485
|
+
return `Granola notes
|
|
486
|
+
|
|
487
|
+
Usage:
|
|
488
|
+
granola notes [options]
|
|
489
|
+
|
|
490
|
+
Options:
|
|
491
|
+
--output <path> Output directory for Markdown files (default: ./notes)
|
|
492
|
+
--timeout <value> Request timeout, e.g. 2m, 30s, 120000 (default: 2m)
|
|
493
|
+
--supabase <path> Path to supabase.json
|
|
494
|
+
--debug Enable debug logging
|
|
495
|
+
--config <path> Path to .granola.toml
|
|
496
|
+
-h, --help Show help
|
|
497
|
+
`;
|
|
498
|
+
}
|
|
499
|
+
const notesCommand = {
|
|
500
|
+
description: "Export Granola notes to Markdown",
|
|
501
|
+
flags: {
|
|
502
|
+
help: { type: "boolean" },
|
|
503
|
+
output: { type: "string" },
|
|
504
|
+
timeout: { type: "string" }
|
|
505
|
+
},
|
|
506
|
+
help: notesHelp,
|
|
507
|
+
name: "notes",
|
|
508
|
+
async run({ commandFlags, globalFlags }) {
|
|
509
|
+
const config = await loadConfig({
|
|
510
|
+
globalFlags,
|
|
511
|
+
subcommandFlags: commandFlags
|
|
512
|
+
});
|
|
513
|
+
if (!config.supabase) throw new Error(`supabase.json not found. Pass --supabase or create .granola.toml. Expected locations include: ${granolaSupabaseCandidates().join(", ")}`);
|
|
514
|
+
debug(config.debug, "using config", config.configFileUsed ?? "(none)");
|
|
515
|
+
debug(config.debug, "supabase", config.supabase);
|
|
516
|
+
debug(config.debug, "timeoutMs", config.notes.timeoutMs);
|
|
517
|
+
debug(config.debug, "output", config.notes.output);
|
|
518
|
+
console.log("Fetching documents from Granola API...");
|
|
519
|
+
const documents = await fetchDocuments({
|
|
520
|
+
supabaseContents: await readFile(config.supabase, "utf8"),
|
|
521
|
+
timeoutMs: config.notes.timeoutMs
|
|
522
|
+
});
|
|
523
|
+
console.log(`Exporting ${documents.length} notes to ${config.notes.output}...`);
|
|
524
|
+
const written = await writeNotes(documents, config.notes.output);
|
|
525
|
+
console.log("✓ Export completed successfully");
|
|
526
|
+
debug(config.debug, "notes written", written);
|
|
527
|
+
return 0;
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
//#endregion
|
|
531
|
+
//#region src/cache.ts
|
|
532
|
+
function parseCacheDocument(id, value) {
|
|
533
|
+
const record = asRecord(value);
|
|
534
|
+
if (!record) return;
|
|
535
|
+
return {
|
|
536
|
+
createdAt: stringValue(record.created_at),
|
|
537
|
+
id,
|
|
538
|
+
title: stringValue(record.title),
|
|
539
|
+
updatedAt: stringValue(record.updated_at)
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
function parseTranscriptSegments(value) {
|
|
543
|
+
if (!Array.isArray(value)) return;
|
|
544
|
+
return value.flatMap((segment) => {
|
|
545
|
+
const record = asRecord(segment);
|
|
546
|
+
if (!record) return [];
|
|
547
|
+
return [{
|
|
548
|
+
documentId: stringValue(record.document_id),
|
|
549
|
+
endTimestamp: stringValue(record.end_timestamp),
|
|
550
|
+
id: stringValue(record.id),
|
|
551
|
+
isFinal: Boolean(record.is_final),
|
|
552
|
+
source: stringValue(record.source),
|
|
553
|
+
startTimestamp: stringValue(record.start_timestamp),
|
|
554
|
+
text: stringValue(record.text)
|
|
555
|
+
}];
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
function parseCacheContents(contents) {
|
|
559
|
+
const outer = parseJsonString(contents);
|
|
560
|
+
if (!outer) throw new Error("failed to parse cache JSON");
|
|
561
|
+
const rawCache = outer.cache;
|
|
562
|
+
let cachePayload;
|
|
563
|
+
if (typeof rawCache === "string") cachePayload = parseJsonString(rawCache);
|
|
564
|
+
else cachePayload = asRecord(rawCache);
|
|
565
|
+
const state = cachePayload ? asRecord(cachePayload.state) : void 0;
|
|
566
|
+
if (!state) throw new Error("failed to parse cache state");
|
|
567
|
+
const rawDocuments = asRecord(state.documents) ?? {};
|
|
568
|
+
const rawTranscripts = asRecord(state.transcripts) ?? {};
|
|
569
|
+
const documents = {};
|
|
570
|
+
for (const [id, rawDocument] of Object.entries(rawDocuments)) {
|
|
571
|
+
const document = parseCacheDocument(id, rawDocument);
|
|
572
|
+
if (document) documents[id] = document;
|
|
573
|
+
}
|
|
574
|
+
const transcripts = {};
|
|
575
|
+
for (const [id, rawTranscript] of Object.entries(rawTranscripts)) {
|
|
576
|
+
const segments = parseTranscriptSegments(rawTranscript);
|
|
577
|
+
if (segments) transcripts[id] = segments;
|
|
578
|
+
}
|
|
579
|
+
return {
|
|
580
|
+
documents,
|
|
581
|
+
transcripts
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
//#endregion
|
|
532
585
|
//#region src/transcripts.ts
|
|
533
586
|
function formatTranscript(document, segments) {
|
|
534
587
|
if (segments.length === 0) return "";
|
|
@@ -576,7 +629,54 @@ async function writeTranscripts(cacheData, outputDir) {
|
|
|
576
629
|
return written;
|
|
577
630
|
}
|
|
578
631
|
//#endregion
|
|
579
|
-
//#region src/
|
|
632
|
+
//#region src/commands/transcripts.ts
|
|
633
|
+
function transcriptsHelp() {
|
|
634
|
+
return `Granola transcripts
|
|
635
|
+
|
|
636
|
+
Usage:
|
|
637
|
+
granola transcripts [options]
|
|
638
|
+
|
|
639
|
+
Options:
|
|
640
|
+
--cache <path> Path to Granola cache JSON
|
|
641
|
+
--output <path> Output directory for transcript files (default: ./transcripts)
|
|
642
|
+
--debug Enable debug logging
|
|
643
|
+
--config <path> Path to .granola.toml
|
|
644
|
+
-h, --help Show help
|
|
645
|
+
`;
|
|
646
|
+
}
|
|
647
|
+
//#endregion
|
|
648
|
+
//#region src/commands/index.ts
|
|
649
|
+
const commands = [notesCommand, {
|
|
650
|
+
description: "Export Granola transcripts to text files",
|
|
651
|
+
flags: {
|
|
652
|
+
cache: { type: "string" },
|
|
653
|
+
help: { type: "boolean" },
|
|
654
|
+
output: { type: "string" }
|
|
655
|
+
},
|
|
656
|
+
help: transcriptsHelp,
|
|
657
|
+
name: "transcripts",
|
|
658
|
+
async run({ commandFlags, globalFlags }) {
|
|
659
|
+
const config = await loadConfig({
|
|
660
|
+
globalFlags,
|
|
661
|
+
subcommandFlags: commandFlags
|
|
662
|
+
});
|
|
663
|
+
if (!config.transcripts.cacheFile) throw new Error(`Granola cache file not found. Pass --cache or create .granola.toml. Expected locations include: ${granolaCacheCandidates().join(", ")}`);
|
|
664
|
+
debug(config.debug, "using config", config.configFileUsed ?? "(none)");
|
|
665
|
+
debug(config.debug, "cacheFile", config.transcripts.cacheFile);
|
|
666
|
+
debug(config.debug, "output", config.transcripts.output);
|
|
667
|
+
console.log("Reading Granola cache file...");
|
|
668
|
+
const cacheData = parseCacheContents(await readFile(config.transcripts.cacheFile, "utf8"));
|
|
669
|
+
const transcriptCount = Object.values(cacheData.transcripts).filter((segments) => segments.length > 0).length;
|
|
670
|
+
console.log(`Exporting ${transcriptCount} transcripts to ${config.transcripts.output}...`);
|
|
671
|
+
const written = await writeTranscripts(cacheData, config.transcripts.output);
|
|
672
|
+
console.log("✓ Export completed successfully");
|
|
673
|
+
debug(config.debug, "transcripts written", written);
|
|
674
|
+
return 0;
|
|
675
|
+
}
|
|
676
|
+
}];
|
|
677
|
+
const commandMap = new Map(commands.map((command) => [command.name, command]));
|
|
678
|
+
//#endregion
|
|
679
|
+
//#region src/flags.ts
|
|
580
680
|
function parseBooleanValue(value) {
|
|
581
681
|
if (/^(true|1|yes|on)$/i.test(value)) return true;
|
|
582
682
|
if (/^(false|0|no|off)$/i.test(value)) return false;
|
|
@@ -624,13 +724,15 @@ function parseFlags(args, spec) {
|
|
|
624
724
|
values
|
|
625
725
|
};
|
|
626
726
|
}
|
|
727
|
+
//#endregion
|
|
728
|
+
//#region src/cli.ts
|
|
627
729
|
function splitCommand(argv) {
|
|
628
|
-
const commands = new Set(["notes", "transcripts"]);
|
|
629
730
|
const rest = [];
|
|
630
731
|
let command;
|
|
631
732
|
for (const token of argv) {
|
|
632
|
-
|
|
633
|
-
|
|
733
|
+
const candidate = !token.startsWith("-") ? commandMap.get(token) : void 0;
|
|
734
|
+
if (!command && candidate) {
|
|
735
|
+
command = candidate;
|
|
634
736
|
continue;
|
|
635
737
|
}
|
|
636
738
|
rest.push(token);
|
|
@@ -641,6 +743,7 @@ function splitCommand(argv) {
|
|
|
641
743
|
};
|
|
642
744
|
}
|
|
643
745
|
function rootHelp() {
|
|
746
|
+
const commandWidth = Math.max(...commands.map((command) => command.name.length));
|
|
644
747
|
return `Granola CLI
|
|
645
748
|
|
|
646
749
|
Export your Granola notes and transcripts.
|
|
@@ -649,8 +752,7 @@ Usage:
|
|
|
649
752
|
granola <command> [options]
|
|
650
753
|
|
|
651
754
|
Commands:
|
|
652
|
-
|
|
653
|
-
transcripts Export Granola transcripts to text files
|
|
755
|
+
${commands.map((command) => ` ${command.name.padEnd(commandWidth)} ${command.description}`).join("\n")}
|
|
654
756
|
|
|
655
757
|
Global options:
|
|
656
758
|
--config <path> Path to .granola.toml
|
|
@@ -663,38 +765,6 @@ Examples:
|
|
|
663
765
|
granola transcripts --cache "${granolaCacheCandidates()[0] ?? "/path/to/cache-v3.json"}"
|
|
664
766
|
`;
|
|
665
767
|
}
|
|
666
|
-
function notesHelp() {
|
|
667
|
-
return `Granola notes
|
|
668
|
-
|
|
669
|
-
Usage:
|
|
670
|
-
granola notes [options]
|
|
671
|
-
|
|
672
|
-
Options:
|
|
673
|
-
--output <path> Output directory for Markdown files (default: ./notes)
|
|
674
|
-
--timeout <value> Request timeout, e.g. 2m, 30s, 120000 (default: 2m)
|
|
675
|
-
--supabase <path> Path to supabase.json
|
|
676
|
-
--debug Enable debug logging
|
|
677
|
-
--config <path> Path to .granola.toml
|
|
678
|
-
-h, --help Show help
|
|
679
|
-
`;
|
|
680
|
-
}
|
|
681
|
-
function transcriptsHelp() {
|
|
682
|
-
return `Granola transcripts
|
|
683
|
-
|
|
684
|
-
Usage:
|
|
685
|
-
granola transcripts [options]
|
|
686
|
-
|
|
687
|
-
Options:
|
|
688
|
-
--cache <path> Path to Granola cache JSON
|
|
689
|
-
--output <path> Output directory for transcript files (default: ./transcripts)
|
|
690
|
-
--debug Enable debug logging
|
|
691
|
-
--config <path> Path to .granola.toml
|
|
692
|
-
-h, --help Show help
|
|
693
|
-
`;
|
|
694
|
-
}
|
|
695
|
-
function debug(enabled, ...values) {
|
|
696
|
-
if (enabled) console.error("[debug]", ...values);
|
|
697
|
-
}
|
|
698
768
|
async function runCli(argv) {
|
|
699
769
|
try {
|
|
700
770
|
const { command, rest } = splitCommand(argv);
|
|
@@ -712,68 +782,15 @@ async function runCli(argv) {
|
|
|
712
782
|
console.log(rootHelp());
|
|
713
783
|
return 1;
|
|
714
784
|
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
output: { type: "string" },
|
|
720
|
-
timeout: { type: "string" }
|
|
721
|
-
});
|
|
722
|
-
if (subcommand.values.help || global.values.help) {
|
|
723
|
-
console.log(notesHelp());
|
|
724
|
-
return 0;
|
|
725
|
-
}
|
|
726
|
-
const config = await loadConfig({
|
|
727
|
-
globalFlags: global.values,
|
|
728
|
-
subcommandFlags: subcommand.values
|
|
729
|
-
});
|
|
730
|
-
if (!config.supabase) throw new Error(`supabase.json not found. Pass --supabase or create .granola.toml. Expected locations include: ${granolaSupabaseCandidates().join(", ")}`);
|
|
731
|
-
debug(config.debug, "using config", config.configFileUsed ?? "(none)");
|
|
732
|
-
debug(config.debug, "supabase", config.supabase);
|
|
733
|
-
debug(config.debug, "timeoutMs", config.notes.timeoutMs);
|
|
734
|
-
debug(config.debug, "output", config.notes.output);
|
|
735
|
-
console.log("Fetching documents from Granola API...");
|
|
736
|
-
const documents = await fetchDocuments({
|
|
737
|
-
supabaseContents: await readFile(config.supabase, "utf8"),
|
|
738
|
-
timeoutMs: config.notes.timeoutMs
|
|
739
|
-
});
|
|
740
|
-
console.log(`Exporting ${documents.length} notes to ${config.notes.output}...`);
|
|
741
|
-
const written = await writeNotes(documents, config.notes.output);
|
|
742
|
-
console.log("✓ Export completed successfully");
|
|
743
|
-
debug(config.debug, "notes written", written);
|
|
744
|
-
return 0;
|
|
745
|
-
}
|
|
746
|
-
case "transcripts": {
|
|
747
|
-
const subcommand = parseFlags(global.rest, {
|
|
748
|
-
cache: { type: "string" },
|
|
749
|
-
help: { type: "boolean" },
|
|
750
|
-
output: { type: "string" }
|
|
751
|
-
});
|
|
752
|
-
if (subcommand.values.help || global.values.help) {
|
|
753
|
-
console.log(transcriptsHelp());
|
|
754
|
-
return 0;
|
|
755
|
-
}
|
|
756
|
-
const config = await loadConfig({
|
|
757
|
-
globalFlags: global.values,
|
|
758
|
-
subcommandFlags: subcommand.values
|
|
759
|
-
});
|
|
760
|
-
if (!config.transcripts.cacheFile) throw new Error(`Granola cache file not found. Pass --cache or create .granola.toml. Expected locations include: ${granolaCacheCandidates().join(", ")}`);
|
|
761
|
-
debug(config.debug, "using config", config.configFileUsed ?? "(none)");
|
|
762
|
-
debug(config.debug, "cacheFile", config.transcripts.cacheFile);
|
|
763
|
-
debug(config.debug, "output", config.transcripts.output);
|
|
764
|
-
console.log("Reading Granola cache file...");
|
|
765
|
-
const cacheData = parseCacheContents(await readFile(config.transcripts.cacheFile, "utf8"));
|
|
766
|
-
const transcriptCount = Object.values(cacheData.transcripts).filter((segments) => segments.length > 0).length;
|
|
767
|
-
console.log(`Exporting ${transcriptCount} transcripts to ${config.transcripts.output}...`);
|
|
768
|
-
const written = await writeTranscripts(cacheData, config.transcripts.output);
|
|
769
|
-
console.log("✓ Export completed successfully");
|
|
770
|
-
debug(config.debug, "transcripts written", written);
|
|
771
|
-
return 0;
|
|
772
|
-
}
|
|
773
|
-
default:
|
|
774
|
-
console.log(rootHelp());
|
|
775
|
-
return 1;
|
|
785
|
+
const subcommand = parseFlags(global.rest, command.flags);
|
|
786
|
+
if (subcommand.values.help || global.values.help) {
|
|
787
|
+
console.log(command.help());
|
|
788
|
+
return 0;
|
|
776
789
|
}
|
|
790
|
+
return await command.run({
|
|
791
|
+
commandFlags: subcommand.values,
|
|
792
|
+
globalFlags: global.values
|
|
793
|
+
});
|
|
777
794
|
} catch (error) {
|
|
778
795
|
const message = error instanceof Error ? error.message : String(error);
|
|
779
796
|
console.error(message);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "granola-toolkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "CLI toolkit for exporting and working with Granola notes and transcripts",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"author": "Nima Karimi",
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
18
|
-
"url": "git
|
|
18
|
+
"url": "git+https://github.com/kkarimi/granola-toolkit.git"
|
|
19
19
|
},
|
|
20
20
|
"bin": {
|
|
21
21
|
"granola": "dist/cli.js"
|