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.
- package/dist/bin/kora.d.ts +3 -0
- package/dist/bin/kora.d.ts.map +1 -0
- package/dist/bin/kora.js +27 -0
- package/dist/bin/kora.js.map +1 -0
- package/dist/src/auth.d.ts +7 -0
- package/dist/src/auth.d.ts.map +1 -0
- package/dist/src/auth.js +39 -0
- package/dist/src/auth.js.map +1 -0
- package/dist/src/cli/backup.d.ts +3 -0
- package/dist/src/cli/backup.d.ts.map +1 -0
- package/dist/src/cli/backup.js +32 -0
- package/dist/src/cli/backup.js.map +1 -0
- package/dist/src/cli/index.d.ts +3 -0
- package/dist/src/cli/index.d.ts.map +1 -0
- package/dist/src/cli/index.js +19 -0
- package/dist/src/cli/index.js.map +1 -0
- package/dist/src/cli/init.d.ts +3 -0
- package/dist/src/cli/init.d.ts.map +1 -0
- package/dist/src/cli/init.js +119 -0
- package/dist/src/cli/init.js.map +1 -0
- package/dist/src/cli/list.d.ts +3 -0
- package/dist/src/cli/list.d.ts.map +1 -0
- package/dist/src/cli/list.js +74 -0
- package/dist/src/cli/list.js.map +1 -0
- package/dist/src/cli/login.d.ts +3 -0
- package/dist/src/cli/login.d.ts.map +1 -0
- package/dist/src/cli/login.js +60 -0
- package/dist/src/cli/login.js.map +1 -0
- package/dist/src/cli/notion.d.ts +3 -0
- package/dist/src/cli/notion.d.ts.map +1 -0
- package/dist/src/cli/notion.js +100 -0
- package/dist/src/cli/notion.js.map +1 -0
- package/dist/src/cli/reset-key.d.ts +3 -0
- package/dist/src/cli/reset-key.d.ts.map +1 -0
- package/dist/src/cli/reset-key.js +57 -0
- package/dist/src/cli/reset-key.js.map +1 -0
- package/dist/src/cli/status.d.ts +3 -0
- package/dist/src/cli/status.d.ts.map +1 -0
- package/dist/src/cli/status.js +36 -0
- package/dist/src/cli/status.js.map +1 -0
- package/dist/src/config.d.ts +12 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +24 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/mcp/server.d.ts +2 -0
- package/dist/src/mcp/server.d.ts.map +1 -0
- package/dist/src/mcp/server.js +23 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/mcp/tools.d.ts +6 -0
- package/dist/src/mcp/tools.d.ts.map +1 -0
- package/dist/src/mcp/tools.js +213 -0
- package/dist/src/mcp/tools.js.map +1 -0
- package/dist/src/storage/sqlite.d.ts +5 -0
- package/dist/src/storage/sqlite.d.ts.map +1 -0
- package/dist/src/storage/sqlite.js +52 -0
- package/dist/src/storage/sqlite.js.map +1 -0
- package/dist/src/ui.d.ts +18 -0
- package/dist/src/ui.d.ts.map +1 -0
- package/dist/src/ui.js +42 -0
- package/dist/src/ui.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { showHeader, successBox, errorBox, spinner } from '../ui.js';
|
|
4
|
+
import { readConfig, writeConfig } from '../config.js';
|
|
5
|
+
export function resetKeyCommand(program) {
|
|
6
|
+
program
|
|
7
|
+
.command('reset-key')
|
|
8
|
+
.description('Generate a new API key (invalidates the old one)')
|
|
9
|
+
.action(async () => {
|
|
10
|
+
showHeader('reset-key');
|
|
11
|
+
const config = readConfig();
|
|
12
|
+
if (!config.key) {
|
|
13
|
+
errorBox('Not logged in. Run `kora login` first.');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const { confirm } = await inquirer.prompt([{
|
|
17
|
+
type: 'confirm',
|
|
18
|
+
name: 'confirm',
|
|
19
|
+
message: chalk.yellow('This will invalidate your current key. Continue?'),
|
|
20
|
+
default: false,
|
|
21
|
+
}]);
|
|
22
|
+
if (!confirm)
|
|
23
|
+
return;
|
|
24
|
+
const spin = spinner('Generating new key...');
|
|
25
|
+
spin.start();
|
|
26
|
+
try {
|
|
27
|
+
const res = await fetch('https://trykora.xyz/api/key/reset', {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
headers: { 'Content-Type': 'application/json' },
|
|
30
|
+
body: JSON.stringify({ key: config.key }),
|
|
31
|
+
});
|
|
32
|
+
const data = await res.json();
|
|
33
|
+
if (!data.key) {
|
|
34
|
+
spin.fail('Failed to reset key');
|
|
35
|
+
errorBox(data.error || 'Could not reset key. Try again or visit trykora.xyz.');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
spin.succeed('New key generated');
|
|
39
|
+
writeConfig({
|
|
40
|
+
...config,
|
|
41
|
+
key: data.key,
|
|
42
|
+
auth: { validatedAt: new Date().toISOString() },
|
|
43
|
+
});
|
|
44
|
+
successBox('Key reset', [
|
|
45
|
+
`New key: ${chalk.cyan(data.key)}`,
|
|
46
|
+
'',
|
|
47
|
+
chalk.dim('Your old key no longer works.'),
|
|
48
|
+
chalk.dim('The new key has been saved to ~/.kora/config.json'),
|
|
49
|
+
].join('\n'));
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
spin.fail('Connection failed');
|
|
53
|
+
errorBox('Could not reach trykora.xyz. Check your internet and try again.');
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=reset-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reset-key.js","sourceRoot":"","sources":["../../../src/cli/reset-key.ts"],"names":[],"mappings":"AACA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEvD,MAAM,UAAU,eAAe,CAAC,OAAgB;IAC9C,OAAO;SACJ,OAAO,CAAC,WAAW,CAAC;SACpB,WAAW,CAAC,kDAAkD,CAAC;SAC/D,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,UAAU,CAAC,WAAW,CAAC,CAAC;QAExB,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,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;gBACzC,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,kDAAkD,CAAC;gBACzE,OAAO,EAAE,KAAK;aACf,CAAC,CAAC,CAAC;QAEJ,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,MAAM,IAAI,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;QAC9C,IAAI,CAAC,KAAK,EAAE,CAAC;QAEb,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,mCAAmC,EAAE;gBAC3D,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC;aAC1C,CAAC,CAAC;YAEH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAS,CAAC;YAErC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACd,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;gBACjC,QAAQ,CAAC,IAAI,CAAC,KAAK,IAAI,sDAAsD,CAAC,CAAC;gBAC/E,OAAO;YACT,CAAC;YAED,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;YAElC,WAAW,CAAC;gBACV,GAAG,MAAM;gBACT,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,IAAI,EAAE,EAAE,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE;aAChD,CAAC,CAAC;YAEH,UAAU,CAAC,WAAW,EAAE;gBACtB,YAAY,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;gBAClC,EAAE;gBACF,KAAK,CAAC,GAAG,CAAC,+BAA+B,CAAC;gBAC1C,KAAK,CAAC,GAAG,CAAC,mDAAmD,CAAC;aAC/D,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAChB,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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/cli/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,QAkC7C"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import dayjs from 'dayjs';
|
|
3
|
+
import relativeTime from 'dayjs/plugin/relativeTime.js';
|
|
4
|
+
import { showHeader, infoBox, errorBox } from '../ui.js';
|
|
5
|
+
import { readConfig } from '../config.js';
|
|
6
|
+
import { getDb } from '../storage/sqlite.js';
|
|
7
|
+
dayjs.extend(relativeTime);
|
|
8
|
+
export function statusCommand(program) {
|
|
9
|
+
program
|
|
10
|
+
.command('status')
|
|
11
|
+
.description('Show your Kora status')
|
|
12
|
+
.action(async () => {
|
|
13
|
+
showHeader('status');
|
|
14
|
+
const config = readConfig();
|
|
15
|
+
if (!config.key) {
|
|
16
|
+
errorBox('Not logged in. Run `kora login` first.');
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const db = getDb();
|
|
20
|
+
const total = db.prepare('SELECT COUNT(*) as n FROM learnings').get().n;
|
|
21
|
+
const weekAgo = new Date(Date.now() - 7 * 86400000).toISOString();
|
|
22
|
+
const weekly = db.prepare('SELECT COUNT(*) as n FROM learnings WHERE created_at >= ?').get(weekAgo).n;
|
|
23
|
+
const last = db.prepare('SELECT created_at FROM learnings ORDER BY created_at DESC LIMIT 1').get();
|
|
24
|
+
const lastSave = last ? dayjs(last.created_at).fromNow() : 'never';
|
|
25
|
+
const maskedKey = config.key.slice(0, 8) + '•'.repeat(config.key.length - 8);
|
|
26
|
+
infoBox('Kora Status', [
|
|
27
|
+
`Key: ${chalk.dim(maskedKey)}`,
|
|
28
|
+
`Plan: ${chalk.bold(config.plan ?? 'free')}`,
|
|
29
|
+
`Notion: ${config.hasNotion ? chalk.green('connected') : chalk.dim('not set up')}`,
|
|
30
|
+
'',
|
|
31
|
+
`Learnings: ${chalk.bold(String(total))} total, ${chalk.bold(String(weekly))} this week`,
|
|
32
|
+
`Last save: ${lastSave}`,
|
|
33
|
+
].join('\n'));
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/cli/status.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,YAAY,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE7C,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;AAE3B,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,uBAAuB,CAAC;SACpC,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,UAAU,CAAC,QAAQ,CAAC,CAAC;QAErB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;QAE5B,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;YAChB,QAAQ,CAAC,wCAAwC,CAAC,CAAC;YACnD,OAAO;QACT,CAAC;QAED,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;QACnB,MAAM,KAAK,GAAI,EAAE,CAAC,OAAO,CAAC,qCAAqC,CAAC,CAAC,GAAG,EAAU,CAAC,CAAC,CAAC;QAEjF,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;QAClE,MAAM,MAAM,GAAI,EAAE,CAAC,OAAO,CAAC,2DAA2D,CAAC,CAAC,GAAG,CAAC,OAAO,CAAS,CAAC,CAAC,CAAC;QAE/G,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,mEAAmE,CAAC,CAAC,GAAG,EAAS,CAAC;QAC1G,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QAEnE,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAE7E,OAAO,CAAC,aAAa,EAAE;YACrB,cAAc,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;YACpC,cAAc,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,EAAE;YACjD,cAAc,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE;YACrF,EAAE;YACF,cAAc,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY;YACxF,cAAc,QAAQ,EAAE;SACzB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAChB,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface KoraConfig {
|
|
2
|
+
key?: string;
|
|
3
|
+
plan?: string;
|
|
4
|
+
hasNotion?: boolean;
|
|
5
|
+
auth?: {
|
|
6
|
+
validatedAt: string;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export declare function readConfig(): KoraConfig;
|
|
10
|
+
export declare function writeConfig(config: KoraConfig): void;
|
|
11
|
+
export declare function getConfigDir(): string;
|
|
12
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE;QACL,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,wBAAgB,UAAU,IAAI,UAAU,CAQvC;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAGpD;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
const CONFIG_DIR = path.join(os.homedir(), '.kora');
|
|
5
|
+
const CONFIG_PATH = path.join(CONFIG_DIR, 'config.json');
|
|
6
|
+
export function readConfig() {
|
|
7
|
+
try {
|
|
8
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
9
|
+
if (!fs.existsSync(CONFIG_PATH))
|
|
10
|
+
return {};
|
|
11
|
+
return JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function writeConfig(config) {
|
|
18
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
19
|
+
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
20
|
+
}
|
|
21
|
+
export function getConfigDir() {
|
|
22
|
+
return CONFIG_DIR;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;AACpD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAWzD,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC;YAAE,OAAO,EAAE,CAAC;QAC3C,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAkB;IAC5C,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,UAAU,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/mcp/server.ts"],"names":[],"mappings":"AAKA,wBAAsB,cAAc,kBAsBnC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { registerTools } from './tools.js';
|
|
4
|
+
import { readConfig } from '../config.js';
|
|
5
|
+
export async function startMcpServer() {
|
|
6
|
+
const config = readConfig();
|
|
7
|
+
if (!config.key) {
|
|
8
|
+
process.stderr.write('Error: No API key found. Run `kora login` first.\n');
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
const server = new McpServer({
|
|
12
|
+
name: 'kora',
|
|
13
|
+
version: '0.1.0',
|
|
14
|
+
});
|
|
15
|
+
registerTools(server, {
|
|
16
|
+
key: config.key,
|
|
17
|
+
hasNotion: config.hasNotion ?? false,
|
|
18
|
+
});
|
|
19
|
+
const transport = new StdioServerTransport();
|
|
20
|
+
await server.connect(transport);
|
|
21
|
+
process.stderr.write('Kora MCP server running on stdio\n');
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/mcp/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oDAAoD,CAAC,CAAC;QAC3E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,aAAa,CAAC,MAAM,EAAE;QACpB,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,KAAK;KACrC,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAUpE,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,QAyP3F"}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ulid } from 'ulid';
|
|
3
|
+
import { getDb, retryUnsynced } from '../storage/sqlite.js';
|
|
4
|
+
import { validateKey } from '../auth.js';
|
|
5
|
+
function bgSync(key) {
|
|
6
|
+
retryUnsynced(key).catch(() => { });
|
|
7
|
+
}
|
|
8
|
+
export function registerTools(server, config) {
|
|
9
|
+
// ── save_learning ──────────────────────────────────────────────
|
|
10
|
+
server.tool('save_learning', [
|
|
11
|
+
'Save a learning from the current session.',
|
|
12
|
+
'Use this whenever the user discovers an insight, makes a mistake, ships something, or learns a lesson worth sharing on X.',
|
|
13
|
+
'Call this proactively when you notice something worth capturing — do not wait to be asked.',
|
|
14
|
+
].join(' '), {
|
|
15
|
+
raw: z.string().describe('The raw insight or learning in the user\'s own words'),
|
|
16
|
+
tags: z.array(z.enum(['win', 'mistake', 'lesson', 'shipit'])).optional(),
|
|
17
|
+
project: z.string().optional().describe('Current project name'),
|
|
18
|
+
}, async ({ raw, tags = [], project }) => {
|
|
19
|
+
await validateKey(config.key, 'save_learning');
|
|
20
|
+
bgSync(config.key);
|
|
21
|
+
const db = getDb();
|
|
22
|
+
const id = ulid();
|
|
23
|
+
const now = new Date().toISOString();
|
|
24
|
+
db.prepare(`
|
|
25
|
+
INSERT INTO learnings (id, raw, tags, project, created_at, synced)
|
|
26
|
+
VALUES (?, ?, ?, ?, ?, 0)
|
|
27
|
+
`).run(id, raw, JSON.stringify(tags), project ?? null, now);
|
|
28
|
+
const total = db.prepare('SELECT COUNT(*) as n FROM learnings').get().n;
|
|
29
|
+
return {
|
|
30
|
+
content: [{
|
|
31
|
+
type: 'text',
|
|
32
|
+
text: [
|
|
33
|
+
`✓ Learning saved (ID: ${id})`,
|
|
34
|
+
`Tags: ${tags.length ? tags.join(', ') : 'none'}`,
|
|
35
|
+
`Total learnings: ${total}`,
|
|
36
|
+
'',
|
|
37
|
+
'You can now:',
|
|
38
|
+
'- "draft a tweet from this learning" — turn it into an X post',
|
|
39
|
+
'- "list my recent learnings" — see everything saved',
|
|
40
|
+
'- "build a thread from my last 5 wins" — create a thread',
|
|
41
|
+
].join('\n'),
|
|
42
|
+
}],
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
// ── list_learnings ─────────────────────────────────────────────
|
|
46
|
+
server.tool('list_learnings', 'Browse saved learnings. Returns a list of learnings with IDs for use in draft_tweet and draft_thread.', {
|
|
47
|
+
tag: z.enum(['win', 'mistake', 'lesson', 'shipit']).optional(),
|
|
48
|
+
limit: z.number().min(1).max(50).optional().default(10),
|
|
49
|
+
since: z.string().optional().describe("'7d', '30d', or ISO date"),
|
|
50
|
+
}, async ({ tag, limit, since }) => {
|
|
51
|
+
await validateKey(config.key, 'list_learnings');
|
|
52
|
+
bgSync(config.key);
|
|
53
|
+
const db = getDb();
|
|
54
|
+
let query = 'SELECT * FROM learnings WHERE 1=1';
|
|
55
|
+
const params = [];
|
|
56
|
+
if (tag) {
|
|
57
|
+
query += ' AND tags LIKE ?';
|
|
58
|
+
params.push(`%${tag}%`);
|
|
59
|
+
}
|
|
60
|
+
if (since) {
|
|
61
|
+
const sinceDate = since.endsWith('d')
|
|
62
|
+
? new Date(Date.now() - parseInt(since) * 86400000).toISOString()
|
|
63
|
+
: new Date(since).toISOString();
|
|
64
|
+
query += ' AND created_at >= ?';
|
|
65
|
+
params.push(sinceDate);
|
|
66
|
+
}
|
|
67
|
+
query += ' ORDER BY created_at DESC LIMIT ?';
|
|
68
|
+
params.push(limit);
|
|
69
|
+
const rows = db.prepare(query).all(...params);
|
|
70
|
+
if (rows.length === 0) {
|
|
71
|
+
return {
|
|
72
|
+
content: [{
|
|
73
|
+
type: 'text',
|
|
74
|
+
text: 'No learnings found. Save one: "save this as a learning: [your insight]"',
|
|
75
|
+
}],
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const formatted = rows.map((r, i) => {
|
|
79
|
+
const tags = JSON.parse(r.tags || '[]');
|
|
80
|
+
return [
|
|
81
|
+
`${i + 1}. ID: ${r.id}`,
|
|
82
|
+
` "${r.raw}"`,
|
|
83
|
+
` Tags: ${tags.join(', ') || 'none'} | ${new Date(r.created_at).toLocaleDateString()} | ${r.tweet_draft ? 'tweet drafted ✓' : 'no draft yet'}`,
|
|
84
|
+
].join('\n');
|
|
85
|
+
}).join('\n\n');
|
|
86
|
+
return {
|
|
87
|
+
content: [{
|
|
88
|
+
type: 'text',
|
|
89
|
+
text: [
|
|
90
|
+
`${rows.length} learning${rows.length === 1 ? '' : 's'} found:\n`,
|
|
91
|
+
formatted,
|
|
92
|
+
'',
|
|
93
|
+
'Use these IDs with draft_tweet or draft_thread.',
|
|
94
|
+
].join('\n'),
|
|
95
|
+
}],
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
// ── draft_tweet ────────────────────────────────────────────────
|
|
99
|
+
server.tool('draft_tweet', [
|
|
100
|
+
'Fetch a saved learning and return it formatted for the AI to turn into a tweet.',
|
|
101
|
+
'The AI should draft a tweet under 280 characters with a strong hook.',
|
|
102
|
+
'After getting this tool result, immediately write the tweet draft — do not ask the user for more input.',
|
|
103
|
+
].join(' '), {
|
|
104
|
+
id: z.string().describe('Learning ID from list_learnings. Use "last" to get the most recent.'),
|
|
105
|
+
style: z.enum(['hook', 'story', 'tip', 'hot-take']).optional().default('hook'),
|
|
106
|
+
}, async ({ id, style }) => {
|
|
107
|
+
await validateKey(config.key, 'draft_tweet');
|
|
108
|
+
bgSync(config.key);
|
|
109
|
+
const db = getDb();
|
|
110
|
+
const learning = id === 'last'
|
|
111
|
+
? db.prepare('SELECT * FROM learnings ORDER BY created_at DESC LIMIT 1').get()
|
|
112
|
+
: db.prepare('SELECT * FROM learnings WHERE id = ?').get(id);
|
|
113
|
+
if (!learning) {
|
|
114
|
+
return {
|
|
115
|
+
content: [{
|
|
116
|
+
type: 'text',
|
|
117
|
+
text: 'Learning not found. Run list_learnings to see available IDs.',
|
|
118
|
+
}],
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
const tags = JSON.parse(learning.tags || '[]');
|
|
122
|
+
return {
|
|
123
|
+
content: [{
|
|
124
|
+
type: 'text',
|
|
125
|
+
text: [
|
|
126
|
+
'## Draft a tweet from this learning',
|
|
127
|
+
'',
|
|
128
|
+
`Learning: "${learning.raw}"`,
|
|
129
|
+
`Tags: ${tags.join(', ') || 'none'}`,
|
|
130
|
+
`Style: ${style}`,
|
|
131
|
+
'',
|
|
132
|
+
'## Tweet drafting rules',
|
|
133
|
+
'- Under 280 characters',
|
|
134
|
+
'- First line must be a hook that stops scrolling',
|
|
135
|
+
'- One concrete insight only — no padding or fluff',
|
|
136
|
+
'- Sound like a real builder, not a marketer',
|
|
137
|
+
'- No buzzwords (game-changer, revolutionary, unlock, etc)',
|
|
138
|
+
'- No emojis unless they genuinely add meaning',
|
|
139
|
+
'- No hashtags',
|
|
140
|
+
'- End with something that makes people want to follow',
|
|
141
|
+
'',
|
|
142
|
+
'## Style guide',
|
|
143
|
+
'hook: Bold opening statement that challenges a common assumption',
|
|
144
|
+
'story: "I did X, it went wrong/right, here\'s what I learned"',
|
|
145
|
+
'tip: Direct actionable advice from first-hand experience',
|
|
146
|
+
'hot-take: Controversial but defensible opinion from your experience',
|
|
147
|
+
'',
|
|
148
|
+
'Now write the tweet. Output only the tweet text, nothing else.',
|
|
149
|
+
].join('\n'),
|
|
150
|
+
}],
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
// ── draft_thread ───────────────────────────────────────────────
|
|
154
|
+
server.tool('draft_thread', [
|
|
155
|
+
'Fetch multiple saved learnings and return them formatted for the AI to turn into an X thread.',
|
|
156
|
+
'The AI should draft a numbered thread with a hook tweet at the top.',
|
|
157
|
+
'After getting this tool result, immediately write the thread — do not ask the user for more input.',
|
|
158
|
+
].join(' '), {
|
|
159
|
+
ids: z.array(z.string()).describe('Learning IDs. Pass ["last5"] to auto-select 5 most recent.'),
|
|
160
|
+
topic: z.string().optional().describe('Optional theme or title for the thread'),
|
|
161
|
+
}, async ({ ids, topic }) => {
|
|
162
|
+
await validateKey(config.key, 'draft_thread');
|
|
163
|
+
bgSync(config.key);
|
|
164
|
+
const db = getDb();
|
|
165
|
+
let learnings;
|
|
166
|
+
if (ids[0] === 'last5') {
|
|
167
|
+
learnings = db.prepare('SELECT * FROM learnings ORDER BY created_at DESC LIMIT 5').all();
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
learnings = ids
|
|
171
|
+
.map(id => db.prepare('SELECT * FROM learnings WHERE id = ?').get(id))
|
|
172
|
+
.filter(Boolean);
|
|
173
|
+
}
|
|
174
|
+
if (learnings.length === 0) {
|
|
175
|
+
return {
|
|
176
|
+
content: [{
|
|
177
|
+
type: 'text',
|
|
178
|
+
text: 'No learnings found. Run list_learnings to see available IDs.',
|
|
179
|
+
}],
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
const learningsList = learnings.map((l, i) => {
|
|
183
|
+
const tags = JSON.parse(l.tags || '[]');
|
|
184
|
+
return `${i + 1}. "${l.raw}" [${tags.join(', ') || 'no tags'}]`;
|
|
185
|
+
}).join('\n');
|
|
186
|
+
return {
|
|
187
|
+
content: [{
|
|
188
|
+
type: 'text',
|
|
189
|
+
text: [
|
|
190
|
+
'## Draft an X thread from these learnings',
|
|
191
|
+
'',
|
|
192
|
+
topic ? `Thread topic: "${topic}"` : '',
|
|
193
|
+
'',
|
|
194
|
+
`Learnings (${learnings.length}):`,
|
|
195
|
+
learningsList,
|
|
196
|
+
'',
|
|
197
|
+
'## Thread drafting rules',
|
|
198
|
+
'- Tweet 1: Hook that makes people want to read the whole thread',
|
|
199
|
+
'- Tweets 2-N: One learning per tweet, concrete and specific',
|
|
200
|
+
'- Last tweet: Summary or call to follow',
|
|
201
|
+
'- Each tweet under 280 characters',
|
|
202
|
+
'- Number each tweet: "1/" "2/" "3/" etc',
|
|
203
|
+
'- No hashtags, no excessive emojis',
|
|
204
|
+
'- Sound like a real builder sharing hard-won lessons',
|
|
205
|
+
'- The hook tweet should tease what\'s coming without giving it away',
|
|
206
|
+
'',
|
|
207
|
+
'Now write the full thread. Output only the numbered tweets separated by blank lines.',
|
|
208
|
+
].filter(Boolean).join('\n'),
|
|
209
|
+
}],
|
|
210
|
+
};
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/mcp/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../../src/storage/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAUtC,wBAAgB,MAAM,SAkBrB;AAED,wBAAgB,KAAK,IAAI,QAAQ,CAAC,QAAQ,CAGzC;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBjE"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
const DB_DIR = path.join(os.homedir(), '.kora');
|
|
6
|
+
const DB_PATH = path.join(DB_DIR, 'learnings.db');
|
|
7
|
+
let db;
|
|
8
|
+
export function initDb() {
|
|
9
|
+
fs.mkdirSync(DB_DIR, { recursive: true });
|
|
10
|
+
db = new Database(DB_PATH);
|
|
11
|
+
db.exec(`
|
|
12
|
+
CREATE TABLE IF NOT EXISTS learnings (
|
|
13
|
+
id TEXT PRIMARY KEY,
|
|
14
|
+
raw TEXT NOT NULL,
|
|
15
|
+
polished TEXT,
|
|
16
|
+
tweet_draft TEXT,
|
|
17
|
+
tags TEXT DEFAULT '[]',
|
|
18
|
+
project TEXT,
|
|
19
|
+
created_at TEXT NOT NULL,
|
|
20
|
+
notion_id TEXT,
|
|
21
|
+
synced INTEGER DEFAULT 0
|
|
22
|
+
);
|
|
23
|
+
CREATE INDEX IF NOT EXISTS idx_created ON learnings(created_at);
|
|
24
|
+
CREATE INDEX IF NOT EXISTS idx_synced ON learnings(synced);
|
|
25
|
+
`);
|
|
26
|
+
}
|
|
27
|
+
export function getDb() {
|
|
28
|
+
if (!db)
|
|
29
|
+
initDb();
|
|
30
|
+
return db;
|
|
31
|
+
}
|
|
32
|
+
export async function retryUnsynced(apiKey) {
|
|
33
|
+
const database = getDb();
|
|
34
|
+
const pending = database.prepare('SELECT * FROM learnings WHERE synced = 0 LIMIT 10').all();
|
|
35
|
+
for (const learning of pending) {
|
|
36
|
+
try {
|
|
37
|
+
const res = await fetch('https://trykora.xyz/api/sync', {
|
|
38
|
+
method: 'POST',
|
|
39
|
+
headers: { 'Content-Type': 'application/json' },
|
|
40
|
+
body: JSON.stringify({ key: apiKey, learning }),
|
|
41
|
+
});
|
|
42
|
+
const { success, notionId } = await res.json();
|
|
43
|
+
if (success) {
|
|
44
|
+
database.prepare('UPDATE learnings SET synced = 1, notion_id = ? WHERE id = ?').run(notionId, learning.id);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Silent fail — retry next tool call
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=sqlite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../../src/storage/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;AAChD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AAElD,IAAI,EAAqB,CAAC;AAE1B,MAAM,UAAU,MAAM;IACpB,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,EAAE,GAAG,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;GAcP,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,KAAK;IACnB,IAAI,CAAC,EAAE;QAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAc;IAChD,MAAM,QAAQ,GAAG,KAAK,EAAE,CAAC;IACzB,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAC9B,mDAAmD,CACpD,CAAC,GAAG,EAAW,CAAC;IAEjB,KAAK,MAAM,QAAQ,IAAI,OAAO,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,8BAA8B,EAAE;gBACtD,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;aAChD,CAAC,CAAC;YACH,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM,GAAG,CAAC,IAAI,EAAS,CAAC;YACtD,IAAI,OAAO,EAAE,CAAC;gBACZ,QAAQ,CAAC,OAAO,CACd,6DAA6D,CAC9D,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,qCAAqC;QACvC,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/dist/src/ui.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import gradient from 'gradient-string';
|
|
2
|
+
import { Ora } from 'ora';
|
|
3
|
+
export declare const brand: gradient.Gradient;
|
|
4
|
+
export declare function showBanner(): void;
|
|
5
|
+
export declare function showHeader(command: string): void;
|
|
6
|
+
export declare function successBox(title: string, body: string): void;
|
|
7
|
+
export declare function infoBox(title: string, body: string): void;
|
|
8
|
+
export declare function errorBox(message: string): void;
|
|
9
|
+
export declare function spinner(text: string): Ora;
|
|
10
|
+
export declare function step(n: number, total: number, text: string): void;
|
|
11
|
+
export declare function divider(): void;
|
|
12
|
+
export declare const funMessages: {
|
|
13
|
+
saving: string[];
|
|
14
|
+
syncing: string[];
|
|
15
|
+
validating: string[];
|
|
16
|
+
};
|
|
17
|
+
export declare function randomMessage(category: keyof typeof funMessages): string;
|
|
18
|
+
//# sourceMappingURL=ui.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/ui.ts"],"names":[],"mappings":"AAEA,OAAO,QAAQ,MAAM,iBAAiB,CAAC;AAEvC,OAAY,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE/B,eAAO,MAAM,KAAK,mBAAmC,CAAC;AAEtD,wBAAgB,UAAU,SAIzB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,QAEzC;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAKrD;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAKlD;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,QAKvC;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAEzC;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAE1D;AAED,wBAAgB,OAAO,SAEtB;AAED,eAAO,MAAM,WAAW;;;;CAIvB,CAAC;AAEF,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,OAAO,WAAW,GAAG,MAAM,CAGxE"}
|
package/dist/src/ui.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import boxen from 'boxen';
|
|
3
|
+
import gradient from 'gradient-string';
|
|
4
|
+
import figlet from 'figlet';
|
|
5
|
+
import ora from 'ora';
|
|
6
|
+
export const brand = gradient(['#f59e0b', '#84cc16']);
|
|
7
|
+
export function showBanner() {
|
|
8
|
+
const text = figlet.textSync('kora', { font: 'Slant' });
|
|
9
|
+
console.log(brand(text));
|
|
10
|
+
console.log(chalk.dim(' your build-in-public brain\n'));
|
|
11
|
+
}
|
|
12
|
+
export function showHeader(command) {
|
|
13
|
+
console.log(chalk.bold.green('◆ kora') + chalk.dim(` › ${command}\n`));
|
|
14
|
+
}
|
|
15
|
+
export function successBox(title, body) {
|
|
16
|
+
console.log(boxen(chalk.bold.green(`✓ ${title}`) + '\n\n' + chalk.white(body), { padding: 1, margin: { top: 1, bottom: 1 }, borderStyle: 'round', borderColor: 'green' }));
|
|
17
|
+
}
|
|
18
|
+
export function infoBox(title, body) {
|
|
19
|
+
console.log(boxen(chalk.bold.cyan(`◆ ${title}`) + '\n\n' + chalk.white(body), { padding: 1, margin: { top: 1, bottom: 1 }, borderStyle: 'round', borderColor: 'cyan' }));
|
|
20
|
+
}
|
|
21
|
+
export function errorBox(message) {
|
|
22
|
+
console.log(boxen(chalk.bold.red('✗ ') + chalk.white(message), { padding: 1, margin: { top: 1, bottom: 1 }, borderStyle: 'round', borderColor: 'red' }));
|
|
23
|
+
}
|
|
24
|
+
export function spinner(text) {
|
|
25
|
+
return ora({ text, color: 'yellow', spinner: 'dots' });
|
|
26
|
+
}
|
|
27
|
+
export function step(n, total, text) {
|
|
28
|
+
console.log(chalk.dim(`[${n}/${total}]`) + ' ' + chalk.white(text));
|
|
29
|
+
}
|
|
30
|
+
export function divider() {
|
|
31
|
+
console.log(chalk.dim('─'.repeat(50)));
|
|
32
|
+
}
|
|
33
|
+
export const funMessages = {
|
|
34
|
+
saving: ['Bottling that insight...', 'Locking in the learning...', 'Noted. Future-you says thanks.'],
|
|
35
|
+
syncing: ['Whispering to Notion...', 'Updating the content calendar...'],
|
|
36
|
+
validating: ['Checking your vibes...', 'Verifying you\'re a real builder...'],
|
|
37
|
+
};
|
|
38
|
+
export function randomMessage(category) {
|
|
39
|
+
const msgs = funMessages[category];
|
|
40
|
+
return msgs[Math.floor(Math.random() * msgs.length)];
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=ui.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/ui.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "trykora",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Your build-in-public brain — works with Claude, Cursor, Windsurf, Antigravity and any MCP-compatible AI tool",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"kora": "./dist/bin/kora.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"dev": "tsx bin/kora.ts",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@modelcontextprotocol/sdk": "latest",
|
|
19
|
+
"better-sqlite3": "^11.0.0",
|
|
20
|
+
"commander": "^12.0.0",
|
|
21
|
+
"chalk": "^5.3.0",
|
|
22
|
+
"ora": "^8.0.0",
|
|
23
|
+
"boxen": "^8.0.0",
|
|
24
|
+
"inquirer": "^9.0.0",
|
|
25
|
+
"cli-table3": "^0.6.3",
|
|
26
|
+
"gradient-string": "^2.0.2",
|
|
27
|
+
"figlet": "^1.7.0",
|
|
28
|
+
"open": "^10.0.0",
|
|
29
|
+
"ulid": "^2.3.0",
|
|
30
|
+
"dayjs": "^1.11.0",
|
|
31
|
+
"zod": "^3.22.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/better-sqlite3": "^7.6.0",
|
|
35
|
+
"@types/figlet": "^1.5.0",
|
|
36
|
+
"@types/gradient-string": "^1.1.0",
|
|
37
|
+
"@types/inquirer": "^9.0.0",
|
|
38
|
+
"@types/node": "^20.0.0",
|
|
39
|
+
"tsx": "^4.0.0",
|
|
40
|
+
"typescript": "^5.0.0"
|
|
41
|
+
},
|
|
42
|
+
"keywords": [
|
|
43
|
+
"mcp",
|
|
44
|
+
"twitter",
|
|
45
|
+
"build-in-public",
|
|
46
|
+
"cli",
|
|
47
|
+
"ai"
|
|
48
|
+
],
|
|
49
|
+
"license": "MIT"
|
|
50
|
+
}
|