trykora 1.0.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.
Files changed (61) hide show
  1. package/dist/bin/kora.d.ts +3 -0
  2. package/dist/bin/kora.d.ts.map +1 -0
  3. package/dist/bin/kora.js +27 -0
  4. package/dist/bin/kora.js.map +1 -0
  5. package/dist/src/auth.d.ts +7 -0
  6. package/dist/src/auth.d.ts.map +1 -0
  7. package/dist/src/auth.js +39 -0
  8. package/dist/src/auth.js.map +1 -0
  9. package/dist/src/cli/backup.d.ts +3 -0
  10. package/dist/src/cli/backup.d.ts.map +1 -0
  11. package/dist/src/cli/backup.js +32 -0
  12. package/dist/src/cli/backup.js.map +1 -0
  13. package/dist/src/cli/index.d.ts +3 -0
  14. package/dist/src/cli/index.d.ts.map +1 -0
  15. package/dist/src/cli/index.js +19 -0
  16. package/dist/src/cli/index.js.map +1 -0
  17. package/dist/src/cli/init.d.ts +3 -0
  18. package/dist/src/cli/init.d.ts.map +1 -0
  19. package/dist/src/cli/init.js +119 -0
  20. package/dist/src/cli/init.js.map +1 -0
  21. package/dist/src/cli/list.d.ts +3 -0
  22. package/dist/src/cli/list.d.ts.map +1 -0
  23. package/dist/src/cli/list.js +74 -0
  24. package/dist/src/cli/list.js.map +1 -0
  25. package/dist/src/cli/login.d.ts +3 -0
  26. package/dist/src/cli/login.d.ts.map +1 -0
  27. package/dist/src/cli/login.js +60 -0
  28. package/dist/src/cli/login.js.map +1 -0
  29. package/dist/src/cli/notion.d.ts +3 -0
  30. package/dist/src/cli/notion.d.ts.map +1 -0
  31. package/dist/src/cli/notion.js +100 -0
  32. package/dist/src/cli/notion.js.map +1 -0
  33. package/dist/src/cli/reset-key.d.ts +3 -0
  34. package/dist/src/cli/reset-key.d.ts.map +1 -0
  35. package/dist/src/cli/reset-key.js +57 -0
  36. package/dist/src/cli/reset-key.js.map +1 -0
  37. package/dist/src/cli/status.d.ts +3 -0
  38. package/dist/src/cli/status.d.ts.map +1 -0
  39. package/dist/src/cli/status.js +36 -0
  40. package/dist/src/cli/status.js.map +1 -0
  41. package/dist/src/config.d.ts +12 -0
  42. package/dist/src/config.d.ts.map +1 -0
  43. package/dist/src/config.js +24 -0
  44. package/dist/src/config.js.map +1 -0
  45. package/dist/src/mcp/server.d.ts +2 -0
  46. package/dist/src/mcp/server.d.ts.map +1 -0
  47. package/dist/src/mcp/server.js +23 -0
  48. package/dist/src/mcp/server.js.map +1 -0
  49. package/dist/src/mcp/tools.d.ts +6 -0
  50. package/dist/src/mcp/tools.d.ts.map +1 -0
  51. package/dist/src/mcp/tools.js +213 -0
  52. package/dist/src/mcp/tools.js.map +1 -0
  53. package/dist/src/storage/sqlite.d.ts +5 -0
  54. package/dist/src/storage/sqlite.d.ts.map +1 -0
  55. package/dist/src/storage/sqlite.js +52 -0
  56. package/dist/src/storage/sqlite.js.map +1 -0
  57. package/dist/src/ui.d.ts +18 -0
  58. package/dist/src/ui.d.ts.map +1 -0
  59. package/dist/src/ui.js +42 -0
  60. package/dist/src/ui.js.map +1 -0
  61. package/package.json +50 -0
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=kora.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kora.d.ts","sourceRoot":"","sources":["../../bin/kora.ts"],"names":[],"mappings":""}
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ import { program } from 'commander';
3
+ import { startMcpServer } from '../src/mcp/server.js';
4
+ program
5
+ .name('kora')
6
+ .description('Your build-in-public brain — capture learnings, draft tweets')
7
+ .version('0.1.0');
8
+ program
9
+ .command('serve')
10
+ .description('Start the MCP stdio server (used by Claude Desktop, Cursor, etc.)')
11
+ .action(async () => {
12
+ await startMcpServer();
13
+ });
14
+ async function main() {
15
+ // Dynamically import CLI commands to avoid loading heavy deps in serve mode
16
+ const { registerCommands } = await import('../src/cli/index.js');
17
+ registerCommands(program);
18
+ program.parse();
19
+ }
20
+ // If running `kora serve`, skip loading CLI deps
21
+ if (process.argv[2] === 'serve') {
22
+ startMcpServer();
23
+ }
24
+ else {
25
+ main();
26
+ }
27
+ //# sourceMappingURL=kora.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kora.js","sourceRoot":"","sources":["../../bin/kora.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO;KACJ,IAAI,CAAC,MAAM,CAAC;KACZ,WAAW,CAAC,8DAA8D,CAAC;KAC3E,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,mEAAmE,CAAC;KAChF,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,cAAc,EAAE,CAAC;AACzB,CAAC,CAAC,CAAC;AAEL,KAAK,UAAU,IAAI;IACjB,4EAA4E;IAC5E,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC;IACjE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC1B,OAAO,CAAC,KAAK,EAAE,CAAC;AAClB,CAAC;AAED,iDAAiD;AACjD,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,EAAE,CAAC;IAChC,cAAc,EAAE,CAAC;AACnB,CAAC;KAAM,CAAC;IACN,IAAI,EAAE,CAAC;AACT,CAAC"}
@@ -0,0 +1,7 @@
1
+ export interface AuthResult {
2
+ valid: boolean;
3
+ plan: string;
4
+ hasNotion: boolean;
5
+ }
6
+ export declare function validateKey(key: string, tool?: string): Promise<AuthResult>;
7
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAoCjF"}
@@ -0,0 +1,39 @@
1
+ import { readConfig, writeConfig } from './config.js';
2
+ const API = 'http://localhost:3000'; //'https://trykora.xyz';
3
+ const CACHE_TTL = 7 * 24 * 60 * 60 * 1000;
4
+ export async function validateKey(key, tool) {
5
+ const config = readConfig();
6
+ if (!tool && config.auth?.validatedAt) {
7
+ const age = Date.now() - new Date(config.auth.validatedAt).getTime();
8
+ if (age < CACHE_TTL) {
9
+ return { valid: true, plan: config.plan ?? 'free', hasNotion: config.hasNotion ?? false };
10
+ }
11
+ }
12
+ try {
13
+ const res = await fetch(`${API}/api/validate`, {
14
+ method: 'POST',
15
+ headers: { 'Content-Type': 'application/json' },
16
+ body: JSON.stringify({ key, tool }),
17
+ });
18
+ const data = await res.json();
19
+ if (data.valid) {
20
+ writeConfig({
21
+ ...config,
22
+ plan: data.plan,
23
+ hasNotion: data.hasNotion,
24
+ auth: { validatedAt: new Date().toISOString() },
25
+ });
26
+ }
27
+ return data;
28
+ }
29
+ catch {
30
+ if (config.auth?.validatedAt) {
31
+ const age = Date.now() - new Date(config.auth.validatedAt).getTime();
32
+ if (age < CACHE_TTL) {
33
+ return { valid: true, plan: config.plan ?? 'free', hasNotion: config.hasNotion ?? false };
34
+ }
35
+ }
36
+ return { valid: false, plan: 'free', hasNotion: false };
37
+ }
38
+ }
39
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEtD,MAAM,GAAG,GAAG,uBAAuB,CAAC,CAAC,wBAAwB;AAC7D,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAQ1C,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW,EAAE,IAAa;IAC1D,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,OAAO,EAAE,CAAC;QACrE,IAAI,GAAG,GAAG,SAAS,EAAE,CAAC;YACpB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,KAAK,EAAE,CAAC;QAC5F,CAAC;IACH,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,GAAG,eAAe,EAAE;YAC7C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;SACpC,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAgB,CAAC;QAE5C,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,WAAW,CAAC;gBACV,GAAG,MAAM;gBACT,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,IAAI,EAAE,EAAE,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE;aAChD,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,OAAO,EAAE,CAAC;YACrE,IAAI,GAAG,GAAG,SAAS,EAAE,CAAC;gBACpB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,KAAK,EAAE,CAAC;YAC5F,CAAC;QACH,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC1D,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function backupCommand(program: Command): void;
3
+ //# sourceMappingURL=backup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup.d.ts","sourceRoot":"","sources":["../../../src/cli/backup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,QA6B7C"}
@@ -0,0 +1,32 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import chalk from 'chalk';
5
+ import dayjs from 'dayjs';
6
+ import { showHeader, successBox, errorBox } from '../ui.js';
7
+ export function backupCommand(program) {
8
+ program
9
+ .command('backup')
10
+ .description('Backup your learnings database to Desktop')
11
+ .action(async () => {
12
+ showHeader('backup');
13
+ const dbPath = path.join(os.homedir(), '.kora', 'learnings.db');
14
+ if (!fs.existsSync(dbPath)) {
15
+ errorBox('No database found at ~/.kora/learnings.db');
16
+ return;
17
+ }
18
+ const desktop = path.join(os.homedir(), 'Desktop');
19
+ const timestamp = dayjs().format('YYYY-MM-DD_HH-mm');
20
+ const backupName = `kora-backup-${timestamp}.db`;
21
+ const dest = path.join(desktop, backupName);
22
+ fs.copyFileSync(dbPath, dest);
23
+ const stats = fs.statSync(dest);
24
+ const sizeKb = (stats.size / 1024).toFixed(1);
25
+ successBox('Backup complete', [
26
+ `File: ${chalk.cyan(backupName)}`,
27
+ `Location: ${chalk.dim(desktop)}`,
28
+ `Size: ${sizeKb} KB`,
29
+ ].join('\n'));
30
+ });
31
+ }
32
+ //# sourceMappingURL=backup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup.js","sourceRoot":"","sources":["../../../src/cli/backup.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAE5D,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,2CAA2C,CAAC;SACxD,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,UAAU,CAAC,QAAQ,CAAC,CAAC;QAErB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;QAChE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3B,QAAQ,CAAC,2CAA2C,CAAC,CAAC;YACtD,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;QACnD,MAAM,SAAS,GAAG,KAAK,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACrD,MAAM,UAAU,GAAG,eAAe,SAAS,KAAK,CAAC;QACjD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QAE5C,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAE9B,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAE9C,UAAU,CAAC,iBAAiB,EAAE;YAC5B,SAAS,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE;YACjC,aAAa,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE;YACjC,SAAS,MAAM,KAAK;SACrB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAChB,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerCommands(program: Command): void;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,QAUhD"}
@@ -0,0 +1,19 @@
1
+ import { showBanner } from '../ui.js';
2
+ import { loginCommand } from './login.js';
3
+ import { initCommand } from './init.js';
4
+ import { statusCommand } from './status.js';
5
+ import { listCommand } from './list.js';
6
+ import { backupCommand } from './backup.js';
7
+ import { notionCommand } from './notion.js';
8
+ import { resetKeyCommand } from './reset-key.js';
9
+ export function registerCommands(program) {
10
+ showBanner();
11
+ loginCommand(program);
12
+ initCommand(program);
13
+ statusCommand(program);
14
+ listCommand(program);
15
+ backupCommand(program);
16
+ notionCommand(program);
17
+ resetKeyCommand(program);
18
+ }
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,UAAU,EAAE,CAAC;IAEb,YAAY,CAAC,OAAO,CAAC,CAAC;IACtB,WAAW,CAAC,OAAO,CAAC,CAAC;IACrB,aAAa,CAAC,OAAO,CAAC,CAAC;IACvB,WAAW,CAAC,OAAO,CAAC,CAAC;IACrB,aAAa,CAAC,OAAO,CAAC,CAAC;IACvB,aAAa,CAAC,OAAO,CAAC,CAAC;IACvB,eAAe,CAAC,OAAO,CAAC,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function initCommand(program: Command): void;
3
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0BpC,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,QAgC3C"}
@@ -0,0 +1,119 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import chalk from 'chalk';
5
+ import inquirer from 'inquirer';
6
+ import { showHeader, successBox, errorBox, step, infoBox } from '../ui.js';
7
+ import { readConfig } from '../config.js';
8
+ function getClaudeConfigPath() {
9
+ const platform = os.platform();
10
+ if (platform === 'darwin') {
11
+ return path.join(os.homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
12
+ }
13
+ else if (platform === 'win32') {
14
+ return path.join(os.homedir(), 'AppData', 'Roaming', 'Claude', 'claude_desktop_config.json');
15
+ }
16
+ return null;
17
+ }
18
+ export function initCommand(program) {
19
+ program
20
+ .command('init')
21
+ .description('Set up Kora in your AI tool (Claude Desktop, Cursor, etc.)')
22
+ .action(async () => {
23
+ showHeader('init');
24
+ const config = readConfig();
25
+ if (!config.key) {
26
+ errorBox('No API key found. Run `kora login` first.');
27
+ return;
28
+ }
29
+ const { tool } = await inquirer.prompt([{
30
+ type: 'list',
31
+ name: 'tool',
32
+ message: 'Which AI tool do you use?',
33
+ choices: [
34
+ { name: 'Claude Desktop', value: 'claude' },
35
+ { name: 'Cursor', value: 'cursor' },
36
+ { name: 'Other (manual setup)', value: 'other' },
37
+ ],
38
+ }]);
39
+ if (tool === 'claude') {
40
+ await setupClaude();
41
+ }
42
+ else if (tool === 'cursor') {
43
+ showCursorInstructions();
44
+ }
45
+ else {
46
+ showManualInstructions();
47
+ }
48
+ });
49
+ }
50
+ async function setupClaude() {
51
+ const configPath = getClaudeConfigPath();
52
+ if (!configPath) {
53
+ errorBox('Could not detect Claude Desktop config path on this platform.');
54
+ showManualInstructions();
55
+ return;
56
+ }
57
+ step(1, 3, 'Detecting Claude Desktop config...');
58
+ let existing = { mcpServers: {} };
59
+ if (fs.existsSync(configPath)) {
60
+ try {
61
+ existing = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
62
+ }
63
+ catch {
64
+ existing = { mcpServers: {} };
65
+ }
66
+ }
67
+ if (existing.mcpServers?.kora) {
68
+ const { overwrite } = await inquirer.prompt([{
69
+ type: 'confirm',
70
+ name: 'overwrite',
71
+ message: chalk.yellow('Kora is already configured in Claude Desktop. Overwrite?'),
72
+ default: false,
73
+ }]);
74
+ if (!overwrite)
75
+ return;
76
+ }
77
+ step(2, 3, 'Adding Kora to Claude Desktop config...');
78
+ existing.mcpServers = existing.mcpServers || {};
79
+ existing.mcpServers.kora = {
80
+ command: 'npx',
81
+ args: ['kora', 'serve'],
82
+ };
83
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
84
+ fs.writeFileSync(configPath, JSON.stringify(existing, null, 2));
85
+ step(3, 3, 'Done!');
86
+ successBox('Claude Desktop configured!', [
87
+ `Config written to: ${chalk.dim(configPath)}`,
88
+ '',
89
+ chalk.yellow('⚠ Restart Claude Desktop to activate Kora.'),
90
+ '',
91
+ 'After restarting, try saying:',
92
+ chalk.cyan(' "save this as a learning: [your insight]"'),
93
+ ].join('\n'));
94
+ }
95
+ function showCursorInstructions() {
96
+ infoBox('Cursor Setup', [
97
+ 'Add this to your Cursor MCP settings:',
98
+ '',
99
+ chalk.cyan(JSON.stringify({
100
+ kora: {
101
+ command: 'npx',
102
+ args: ['kora', 'serve'],
103
+ },
104
+ }, null, 2)),
105
+ '',
106
+ 'Or add it to your project\'s .cursor/mcp.json file.',
107
+ ].join('\n'));
108
+ }
109
+ function showManualInstructions() {
110
+ infoBox('Manual Setup', [
111
+ 'Add this MCP server config to your AI tool:',
112
+ '',
113
+ ` Command: ${chalk.cyan('npx')}`,
114
+ ` Args: ${chalk.cyan('["kora", "serve"]')}`,
115
+ '',
116
+ 'The MCP server communicates over stdio.',
117
+ ].join('\n'));
118
+ }
119
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function listCommand(program: Command): void;
3
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/cli/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAepC,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,QAuE3C"}
@@ -0,0 +1,74 @@
1
+ import chalk from 'chalk';
2
+ import Table from 'cli-table3';
3
+ import dayjs from 'dayjs';
4
+ import { showHeader, errorBox } from '../ui.js';
5
+ import { readConfig } from '../config.js';
6
+ import { getDb } from '../storage/sqlite.js';
7
+ const TAG_COLORS = {
8
+ win: chalk.green,
9
+ mistake: chalk.red,
10
+ lesson: chalk.yellow,
11
+ shipit: chalk.magenta,
12
+ };
13
+ export function listCommand(program) {
14
+ program
15
+ .command('list')
16
+ .description('List your saved learnings')
17
+ .option('--tag <tag>', 'Filter by tag (win, mistake, lesson, shipit)')
18
+ .option('--limit <n>', 'Number of learnings to show', '10')
19
+ .option('--since <period>', 'Time period (7d, 30d, or ISO date)')
20
+ .option('--json', 'Output as JSON')
21
+ .action(async (opts) => {
22
+ showHeader('list');
23
+ const config = readConfig();
24
+ if (!config.key) {
25
+ errorBox('Not logged in. Run `kora login` first.');
26
+ return;
27
+ }
28
+ const db = getDb();
29
+ let query = 'SELECT * FROM learnings WHERE 1=1';
30
+ const params = [];
31
+ if (opts.tag) {
32
+ query += ' AND tags LIKE ?';
33
+ params.push(`%${opts.tag}%`);
34
+ }
35
+ if (opts.since) {
36
+ const sinceDate = opts.since.endsWith('d')
37
+ ? new Date(Date.now() - parseInt(opts.since) * 86400000).toISOString()
38
+ : new Date(opts.since).toISOString();
39
+ query += ' AND created_at >= ?';
40
+ params.push(sinceDate);
41
+ }
42
+ query += ' ORDER BY created_at DESC LIMIT ?';
43
+ params.push(parseInt(opts.limit));
44
+ const rows = db.prepare(query).all(...params);
45
+ if (rows.length === 0) {
46
+ console.log(chalk.dim('\n No learnings found. Save one in your AI tool!\n'));
47
+ return;
48
+ }
49
+ if (opts.json) {
50
+ console.log(JSON.stringify(rows, null, 2));
51
+ return;
52
+ }
53
+ const table = new Table({
54
+ head: ['#', 'Learning', 'Tags', 'Date', 'Synced'].map(h => chalk.cyan(h)),
55
+ colWidths: [4, 50, 14, 12, 8],
56
+ wordWrap: true,
57
+ style: { 'padding-left': 1, 'padding-right': 1 },
58
+ });
59
+ rows.forEach((r, i) => {
60
+ const tags = JSON.parse(r.tags || '[]');
61
+ const coloredTags = tags.map((t) => (TAG_COLORS[t] ?? chalk.white)(t)).join(', ');
62
+ table.push([
63
+ chalk.dim(String(i + 1)),
64
+ r.raw.length > 47 ? r.raw.slice(0, 47) + '...' : r.raw,
65
+ coloredTags || chalk.dim('none'),
66
+ dayjs(r.created_at).format('MMM D'),
67
+ r.synced ? chalk.green('✓') : chalk.dim('—'),
68
+ ]);
69
+ });
70
+ console.log(table.toString());
71
+ console.log(chalk.dim(`\n Showing ${rows.length} learning${rows.length === 1 ? '' : 's'}\n`));
72
+ });
73
+ }
74
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/cli/list.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function loginCommand(program: Command): void;
3
+ //# sourceMappingURL=login.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../../src/cli/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,QA6D5C"}
@@ -0,0 +1,60 @@
1
+ import inquirer from 'inquirer';
2
+ import open from 'open';
3
+ import chalk from 'chalk';
4
+ import { showHeader, successBox, errorBox, spinner, randomMessage, step } from '../ui.js';
5
+ import { readConfig, writeConfig } from '../config.js';
6
+ import { validateKey } from '../auth.js';
7
+ export function loginCommand(program) {
8
+ program
9
+ .command('login')
10
+ .description('Authenticate with your Kora API key')
11
+ .action(async () => {
12
+ showHeader('login');
13
+ const config = readConfig();
14
+ if (config.key) {
15
+ const { overwrite } = await inquirer.prompt([{
16
+ type: 'confirm',
17
+ name: 'overwrite',
18
+ message: chalk.yellow('You already have an API key configured. Overwrite?'),
19
+ default: false,
20
+ }]);
21
+ if (!overwrite)
22
+ return;
23
+ }
24
+ step(1, 3, 'Opening trykora.xyz/sign-up in your browser...');
25
+ await open('https://trykora.xyz/sign-up');
26
+ console.log(chalk.dim('\n If the browser didn\'t open, visit: https://trykora.xyz/sign-up\n'));
27
+ const { key } = await inquirer.prompt([{
28
+ type: 'password',
29
+ name: 'key',
30
+ message: 'Paste your API key:',
31
+ mask: '•',
32
+ validate: (input) => input.startsWith('kora_') ? true : 'API key should start with kora_',
33
+ }]);
34
+ const spin = spinner(randomMessage('validating'));
35
+ spin.start();
36
+ step(2, 3, 'Validating key...');
37
+ const result = await validateKey(key);
38
+ if (!result.valid) {
39
+ spin.fail('Invalid API key');
40
+ errorBox('That key didn\'t work. Double-check it on trykora.xyz/success');
41
+ return;
42
+ }
43
+ spin.succeed('Key validated');
44
+ step(3, 3, 'Saving to ~/.kora/config.json');
45
+ writeConfig({
46
+ ...config,
47
+ key,
48
+ plan: result.plan,
49
+ hasNotion: result.hasNotion,
50
+ auth: { validatedAt: new Date().toISOString() },
51
+ });
52
+ successBox('Logged in!', [
53
+ `Plan: ${chalk.bold(result.plan)}`,
54
+ `Notion: ${result.hasNotion ? chalk.green('connected') : chalk.dim('not set up')}`,
55
+ '',
56
+ `Next: run ${chalk.cyan('kora init')} to set up your AI tool`,
57
+ ].join('\n'));
58
+ });
59
+ }
60
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../../src/cli/login.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function notionCommand(program: Command): void;
3
+ //# sourceMappingURL=notion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notion.d.ts","sourceRoot":"","sources":["../../../src/cli/notion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,QAoG7C"}
@@ -0,0 +1,100 @@
1
+ import inquirer from 'inquirer';
2
+ import open from 'open';
3
+ import chalk from 'chalk';
4
+ import { showHeader, successBox, errorBox, spinner, step, infoBox } from '../ui.js';
5
+ import { readConfig, writeConfig } from '../config.js';
6
+ export function notionCommand(program) {
7
+ program
8
+ .command('notion')
9
+ .description('Connect your Notion workspace for content calendar sync')
10
+ .action(async () => {
11
+ showHeader('notion');
12
+ const config = readConfig();
13
+ if (!config.key) {
14
+ errorBox('Not logged in. Run `kora login` first.');
15
+ return;
16
+ }
17
+ infoBox('Notion Setup', [
18
+ 'Kora syncs your learnings to a Notion database.',
19
+ 'You\'ll need a Notion integration token.',
20
+ '',
21
+ 'We\'ll open the Notion integrations page for you.',
22
+ ].join('\n'));
23
+ const { ready } = await inquirer.prompt([{
24
+ type: 'confirm',
25
+ name: 'ready',
26
+ message: 'Open Notion integrations page?',
27
+ default: true,
28
+ }]);
29
+ if (ready) {
30
+ await open('https://www.notion.so/my-integrations');
31
+ console.log(chalk.dim('\n Create a new integration, then copy the token.\n'));
32
+ }
33
+ const { notionToken } = await inquirer.prompt([{
34
+ type: 'password',
35
+ name: 'notionToken',
36
+ message: 'Paste your Notion integration token:',
37
+ mask: '•',
38
+ validate: (input) => input.startsWith('ntn_') || input.startsWith('secret_')
39
+ ? true
40
+ : 'Token should start with ntn_ or secret_',
41
+ }]);
42
+ const { createDb } = await inquirer.prompt([{
43
+ type: 'confirm',
44
+ name: 'createDb',
45
+ message: 'Create a new "Kora Learnings" database in Notion?',
46
+ default: true,
47
+ }]);
48
+ let parentPageId;
49
+ if (createDb) {
50
+ const { pageId } = await inquirer.prompt([{
51
+ type: 'input',
52
+ name: 'pageId',
53
+ message: 'Paste the parent page ID (or URL) where the database should be created:',
54
+ validate: (input) => input.length > 0 ? true : 'Please provide a page ID or URL',
55
+ }]);
56
+ parentPageId = extractNotionId(pageId);
57
+ }
58
+ const spin = spinner('Connecting to Notion...');
59
+ spin.start();
60
+ try {
61
+ step(1, 2, 'Saving Notion credentials...');
62
+ const res = await fetch('https://trykora.xyz/api/notion', {
63
+ method: 'POST',
64
+ headers: { 'Content-Type': 'application/json' },
65
+ body: JSON.stringify({
66
+ key: config.key,
67
+ notionToken,
68
+ parentPageId,
69
+ createDb,
70
+ }),
71
+ });
72
+ const data = await res.json();
73
+ if (!data.success) {
74
+ spin.fail('Connection failed');
75
+ errorBox(data.reason || 'Could not connect to Notion. Check your token and try again.');
76
+ return;
77
+ }
78
+ spin.succeed('Connected to Notion');
79
+ step(2, 2, 'Updating local config...');
80
+ writeConfig({ ...config, hasNotion: true });
81
+ successBox('Notion connected!', [
82
+ data.dbName ? `Database: ${chalk.cyan(data.dbName)}` : '',
83
+ '',
84
+ 'Your learnings will now sync to Notion automatically.',
85
+ `View them at: ${chalk.dim('notion.so')}`,
86
+ ].filter(Boolean).join('\n'));
87
+ }
88
+ catch {
89
+ spin.fail('Connection failed');
90
+ errorBox('Could not reach trykora.xyz. Check your internet and try again.');
91
+ }
92
+ });
93
+ }
94
+ function extractNotionId(input) {
95
+ const match = input.match(/([a-f0-9]{32})/);
96
+ if (match)
97
+ return match[1];
98
+ return input.replace(/-/g, '');
99
+ }
100
+ //# sourceMappingURL=notion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notion.js","sourceRoot":"","sources":["../../../src/cli/notion.ts"],"names":[],"mappings":"AACA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACpF,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEvD,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,yDAAyD,CAAC;SACtE,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,UAAU,CAAC,QAAQ,CAAC,CAAC;QAErB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;YAChB,QAAQ,CAAC,wCAAwC,CAAC,CAAC;YACnD,OAAO;QACT,CAAC;QAED,OAAO,CAAC,cAAc,EAAE;YACtB,iDAAiD;YACjD,0CAA0C;YAC1C,EAAE;YACF,mDAAmD;SACpD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAEd,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;gBACvC,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,OAAO;gBACb,OAAO,EAAE,gCAAgC;gBACzC,OAAO,EAAE,IAAI;aACd,CAAC,CAAC,CAAC;QAEJ,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,IAAI,CAAC,uCAAuC,CAAC,CAAC;YACpD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC,CAAC;QACjF,CAAC;QAED,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;gBAC7C,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,aAAa;gBACnB,OAAO,EAAE,sCAAsC;gBAC/C,IAAI,EAAE,GAAG;gBACT,QAAQ,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC;oBAClF,CAAC,CAAC,IAAI;oBACN,CAAC,CAAC,yCAAyC;aAC9C,CAAC,CAAC,CAAC;QAEJ,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;gBAC1C,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,mDAAmD;gBAC5D,OAAO,EAAE,IAAI;aACd,CAAC,CAAC,CAAC;QAEJ,IAAI,YAAgC,CAAC;QACrC,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;oBACxC,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,yEAAyE;oBAClF,QAAQ,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,iCAAiC;iBACzF,CAAC,CAAC,CAAC;YACJ,YAAY,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;QACzC,CAAC;QAED,MAAM,IAAI,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC;QAChD,IAAI,CAAC,KAAK,EAAE,CAAC;QAEb,IAAI,CAAC;YACH,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,8BAA8B,CAAC,CAAC;YAC3C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,gCAAgC,EAAE;gBACxD,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,GAAG,EAAE,MAAM,CAAC,GAAG;oBACf,WAAW;oBACX,YAAY;oBACZ,QAAQ;iBACT,CAAC;aACH,CAAC,CAAC;YAEH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAS,CAAC;YAErC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAClB,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;gBAC/B,QAAQ,CAAC,IAAI,CAAC,MAAM,IAAI,8DAA8D,CAAC,CAAC;gBACxF,OAAO;YACT,CAAC;YAED,IAAI,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC;YACpC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,0BAA0B,CAAC,CAAC;YAEvC,WAAW,CAAC,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAE5C,UAAU,CAAC,mBAAmB,EAAE;gBAC9B,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;gBACzD,EAAE;gBACF,uDAAuD;gBACvD,iBAAiB,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE;aAC1C,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YAC/B,QAAQ,CAAC,iEAAiE,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC;AAED,SAAS,eAAe,CAAC,KAAa;IACpC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC5C,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3B,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function resetKeyCommand(program: Command): void;
3
+ //# sourceMappingURL=reset-key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reset-key.d.ts","sourceRoot":"","sources":["../../../src/cli/reset-key.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,QA2D/C"}