kaimon-cli 0.1.2 ā 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +71 -32
- package/bin/index.js +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +13 -4
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/pull.d.ts +4 -0
- package/dist/commands/pull.d.ts.map +1 -0
- package/dist/commands/pull.js +20 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/push.d.ts +4 -0
- package/dist/commands/push.d.ts.map +1 -0
- package/dist/commands/push.js +19 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +3 -14
- package/dist/commands/sync.js.map +1 -1
- package/dist/config/constants.d.ts +1 -1
- package/dist/config/constants.d.ts.map +1 -1
- package/dist/config/constants.js +7 -3
- package/dist/config/constants.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/markdown.d.ts +21 -0
- package/dist/utils/markdown.d.ts.map +1 -0
- package/dist/utils/markdown.js +180 -0
- package/dist/utils/markdown.js.map +1 -0
- package/dist/utils/projectConfig.d.ts +25 -0
- package/dist/utils/projectConfig.d.ts.map +1 -0
- package/dist/utils/projectConfig.js +160 -0
- package/dist/utils/projectConfig.js.map +1 -0
- package/dist/utils/supabaseClient.d.ts +11 -0
- package/dist/utils/supabaseClient.d.ts.map +1 -0
- package/dist/utils/supabaseClient.js +43 -0
- package/dist/utils/supabaseClient.js.map +1 -0
- package/dist/utils/syncOperations.d.ts +16 -0
- package/dist/utils/syncOperations.d.ts.map +1 -0
- package/dist/utils/syncOperations.js +168 -0
- package/dist/utils/syncOperations.js.map +1 -0
- package/package.json +15 -8
- package/src/commands/auth.ts +0 -170
- package/src/commands/config.ts +0 -72
- package/src/commands/sync.ts +0 -30
- package/src/config/constants.ts +0 -27
- package/src/index.ts +0 -20
- package/src/utils/config.ts +0 -81
- package/src/utils/requireAuth.ts +0 -65
- package/tsconfig.json +0 -21
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import readline from 'readline/promises';
|
|
5
|
+
const CONFIG_DIR = '.kaimon';
|
|
6
|
+
const CONFIG_FILE = 'config.json';
|
|
7
|
+
const CONFIG_VERSION = '1.0.0';
|
|
8
|
+
// Get project config directory path
|
|
9
|
+
export function getProjectConfigDir(baseDir = process.cwd()) {
|
|
10
|
+
return path.join(baseDir, CONFIG_DIR);
|
|
11
|
+
}
|
|
12
|
+
// Get project config file path
|
|
13
|
+
export function getProjectConfigPath(baseDir = process.cwd()) {
|
|
14
|
+
return path.join(getProjectConfigDir(baseDir), CONFIG_FILE);
|
|
15
|
+
}
|
|
16
|
+
// Check if project is initialized
|
|
17
|
+
export function isProjectInitialized(baseDir = process.cwd()) {
|
|
18
|
+
return fs.existsSync(getProjectConfigPath(baseDir));
|
|
19
|
+
}
|
|
20
|
+
// Load project config
|
|
21
|
+
export function loadProjectConfig(baseDir = process.cwd()) {
|
|
22
|
+
const configPath = getProjectConfigPath(baseDir);
|
|
23
|
+
if (!fs.existsSync(configPath)) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
28
|
+
return JSON.parse(content);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
throw new Error(`Failed to load project config: ${error}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Save project config
|
|
35
|
+
export function saveProjectConfig(config, baseDir = process.cwd()) {
|
|
36
|
+
const configDir = getProjectConfigDir(baseDir);
|
|
37
|
+
const configPath = getProjectConfigPath(baseDir);
|
|
38
|
+
// Ensure directory exists
|
|
39
|
+
if (!fs.existsSync(configDir)) {
|
|
40
|
+
fs.mkdirSync(configDir, { recursive: true, mode: 0o755 });
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), {
|
|
44
|
+
mode: 0o644
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
throw new Error(`Failed to save project config: ${error}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Validate project config
|
|
52
|
+
export function validateProjectConfig(config) {
|
|
53
|
+
const errors = [];
|
|
54
|
+
if (!config.version) {
|
|
55
|
+
errors.push('Missing version field');
|
|
56
|
+
}
|
|
57
|
+
if (!config.user_id) {
|
|
58
|
+
errors.push('Missing user_id field');
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
valid: errors.length === 0,
|
|
62
|
+
errors
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
// Find project config by walking up directory tree
|
|
66
|
+
export function findProjectConfig(startDir = process.cwd()) {
|
|
67
|
+
let currentDir = startDir;
|
|
68
|
+
const root = path.parse(currentDir).root;
|
|
69
|
+
while (currentDir !== root) {
|
|
70
|
+
const configPath = getProjectConfigPath(currentDir);
|
|
71
|
+
if (fs.existsSync(configPath)) {
|
|
72
|
+
const config = loadProjectConfig(currentDir);
|
|
73
|
+
if (config) {
|
|
74
|
+
return { path: currentDir, config };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Move up one directory
|
|
78
|
+
const parentDir = path.dirname(currentDir);
|
|
79
|
+
if (parentDir === currentDir)
|
|
80
|
+
break; // Reached root
|
|
81
|
+
currentDir = parentDir;
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
// Initialize project config with user interaction
|
|
86
|
+
export async function initProjectConfig(baseDir = process.cwd()) {
|
|
87
|
+
// Check if already initialized
|
|
88
|
+
if (isProjectInitialized(baseDir)) {
|
|
89
|
+
console.log(chalk.yellow('ā ļø This directory is already initialized'));
|
|
90
|
+
console.log(chalk.gray(`Config: ${getProjectConfigPath(baseDir)}\n`));
|
|
91
|
+
// Ask if they want to reconfigure
|
|
92
|
+
const rl = readline.createInterface({
|
|
93
|
+
input: process.stdin,
|
|
94
|
+
output: process.stdout
|
|
95
|
+
});
|
|
96
|
+
const answer = await rl.question(chalk.cyan('Do you want to reinitialize? (y/N): '));
|
|
97
|
+
rl.close();
|
|
98
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
99
|
+
console.log(chalk.gray('Initialization cancelled\n'));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Get user ID from global config
|
|
104
|
+
const { loadConfig } = await import('./config.js');
|
|
105
|
+
const globalConfig = loadConfig();
|
|
106
|
+
if (!globalConfig.access_token) {
|
|
107
|
+
throw new Error('Not authenticated. Run "kaimon auth login" first.');
|
|
108
|
+
}
|
|
109
|
+
// For now, we'll store just the user ID
|
|
110
|
+
// In the future, we can add workspace/folder selection
|
|
111
|
+
const config = {
|
|
112
|
+
version: CONFIG_VERSION,
|
|
113
|
+
user_id: globalConfig.user_email || 'default',
|
|
114
|
+
sync_patterns: {
|
|
115
|
+
include: ['**/*.md'],
|
|
116
|
+
exclude: ['node_modules/**', '.git/**', 'dist/**', 'build/**']
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
// Save config
|
|
120
|
+
saveProjectConfig(config, baseDir);
|
|
121
|
+
console.log(chalk.green('ā
Initialized Kaimon sync!'));
|
|
122
|
+
console.log(chalk.gray(`Config saved to: ${getProjectConfigPath(baseDir)}`));
|
|
123
|
+
console.log(chalk.gray('\nYou can now use:'));
|
|
124
|
+
console.log(chalk.cyan(' kaimon sync --pull') + chalk.gray(' # Download docs from Kaimon'));
|
|
125
|
+
console.log(chalk.cyan(' kaimon sync --push') + chalk.gray(' # Upload docs to Kaimon'));
|
|
126
|
+
console.log(chalk.cyan(' kaimon sync --diff') + chalk.gray(' # Preview changes\n'));
|
|
127
|
+
// Show what will be synced
|
|
128
|
+
console.log(chalk.blue('š Sync Configuration:'));
|
|
129
|
+
if (config.sync_patterns) {
|
|
130
|
+
console.log(chalk.gray(' Include patterns:'));
|
|
131
|
+
config.sync_patterns.include.forEach(pattern => {
|
|
132
|
+
console.log(chalk.dim(` - ${pattern}`));
|
|
133
|
+
});
|
|
134
|
+
console.log(chalk.gray(' Exclude patterns:'));
|
|
135
|
+
config.sync_patterns.exclude.forEach(pattern => {
|
|
136
|
+
console.log(chalk.dim(` - ${pattern}`));
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
console.log();
|
|
140
|
+
}
|
|
141
|
+
// Require project config (throws if not found)
|
|
142
|
+
export async function requireProjectConfig(baseDir = process.cwd()) {
|
|
143
|
+
const found = findProjectConfig(baseDir);
|
|
144
|
+
if (!found) {
|
|
145
|
+
console.log(chalk.red('\nā Not in a Kaimon project'));
|
|
146
|
+
console.log(chalk.yellow('Please initialize first:'));
|
|
147
|
+
console.log(chalk.cyan(' kaimon config init\n'));
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
const { valid, errors } = validateProjectConfig(found.config);
|
|
151
|
+
if (!valid) {
|
|
152
|
+
console.log(chalk.red('\nā Invalid project configuration'));
|
|
153
|
+
errors.forEach(error => console.log(chalk.yellow(` - ${error}`)));
|
|
154
|
+
console.log(chalk.gray('\nPlease reinitialize:'));
|
|
155
|
+
console.log(chalk.cyan(' kaimon config init\n'));
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
return found.config;
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=projectConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectConfig.js","sourceRoot":"","sources":["../../src/utils/projectConfig.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SupabaseClient } from '@supabase/supabase-js';
|
|
2
|
+
/**
|
|
3
|
+
* Get authenticated Supabase client
|
|
4
|
+
* Uses the access token from the CLI config
|
|
5
|
+
*/
|
|
6
|
+
export declare function getSupabaseClient(): SupabaseClient;
|
|
7
|
+
/**
|
|
8
|
+
* Reset the Supabase client (useful after logout/login)
|
|
9
|
+
*/
|
|
10
|
+
export declare function resetSupabaseClient(): void;
|
|
11
|
+
//# sourceMappingURL=supabaseClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supabaseClient.d.ts","sourceRoot":"","sources":["../../src/utils/supabaseClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAqBrE;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,CAsBlD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createClient } from '@supabase/supabase-js';
|
|
2
|
+
import { loadConfig } from './config.js';
|
|
3
|
+
import { SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY } from '../config/constants.js';
|
|
4
|
+
let supabaseInstance = null;
|
|
5
|
+
// Validate that constants are configured
|
|
6
|
+
if (!SUPABASE_URL || SUPABASE_URL.includes('YOUR_PROJECT_ID')) {
|
|
7
|
+
throw new Error('Supabase URL not configured in constants.ts\n' +
|
|
8
|
+
'Please update SUPABASE_URL in cli/src/config/constants.ts with your actual Supabase project URL.');
|
|
9
|
+
}
|
|
10
|
+
if (!SUPABASE_PUBLISHABLE_KEY || SUPABASE_PUBLISHABLE_KEY.includes('...')) {
|
|
11
|
+
throw new Error('Supabase publishable key not configured in constants.ts\n' +
|
|
12
|
+
'Please update SUPABASE_PUBLISHABLE_KEY in cli/src/config/constants.ts with your actual publishable key.');
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get authenticated Supabase client
|
|
16
|
+
* Uses the access token from the CLI config
|
|
17
|
+
*/
|
|
18
|
+
export function getSupabaseClient() {
|
|
19
|
+
if (supabaseInstance) {
|
|
20
|
+
return supabaseInstance;
|
|
21
|
+
}
|
|
22
|
+
// Load config to get access token
|
|
23
|
+
const config = loadConfig();
|
|
24
|
+
if (!config.access_token) {
|
|
25
|
+
throw new Error('Not authenticated. Please run "kaimon auth login" first.');
|
|
26
|
+
}
|
|
27
|
+
// Create Supabase client with user's access token
|
|
28
|
+
supabaseInstance = createClient(SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY, {
|
|
29
|
+
global: {
|
|
30
|
+
headers: {
|
|
31
|
+
Authorization: `Bearer ${config.access_token}`
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return supabaseInstance;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Reset the Supabase client (useful after logout/login)
|
|
39
|
+
*/
|
|
40
|
+
export function resetSupabaseClient() {
|
|
41
|
+
supabaseInstance = null;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=supabaseClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supabaseClient.js","sourceRoot":"","sources":["../../src/utils/supabaseClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAkB,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAEhF,IAAI,gBAAgB,GAA0B,IAAI,CAAC;AAEnD,yCAAyC;AACzC,IAAI,CAAC,YAAY,IAAI,YAAY,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC;IAC9D,MAAM,IAAI,KAAK,CACb,+CAA+C;QAC/C,kGAAkG,CACnG,CAAC;AACJ,CAAC;AAED,IAAI,CAAC,wBAAwB,IAAI,wBAAwB,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;IAC1E,MAAM,IAAI,KAAK,CACb,2DAA2D;QAC3D,yGAAyG,CAC1G,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,gBAAgB,EAAE,CAAC;QACrB,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED,kCAAkC;IAClC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IAED,kDAAkD;IAClD,gBAAgB,GAAG,YAAY,CAAC,YAAY,EAAE,wBAAwB,EAAE;QACtE,MAAM,EAAE;YACN,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,MAAM,CAAC,YAAY,EAAE;aAC/C;SACF;KACF,CAAC,CAAC;IAEH,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB;IACjC,gBAAgB,GAAG,IAAI,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pull all documents from Kaimon and save as markdown files
|
|
3
|
+
* @param flat - If true, save directly to current folder; if false, create KaimonDocs/ subfolder
|
|
4
|
+
*/
|
|
5
|
+
export declare function pullDocuments(flat?: boolean): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* Push local markdown files to Kaimon
|
|
8
|
+
* TODO: Implement in Phase 3
|
|
9
|
+
*/
|
|
10
|
+
export declare function pushDocuments(): Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* Show diff between local and remote
|
|
13
|
+
* TODO: Implement in Phase 3
|
|
14
|
+
*/
|
|
15
|
+
export declare function showDiff(): Promise<void>;
|
|
16
|
+
//# sourceMappingURL=syncOperations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"syncOperations.d.ts","sourceRoot":"","sources":["../../src/utils/syncOperations.ts"],"names":[],"mappings":"AA6CA;;;GAGG;AACH,wBAAsB,aAAa,CAAC,IAAI,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAoJxE;AAED;;;GAGG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnD;AAED;;;GAGG;AACH,wBAAsB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAE9C"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import ora from 'ora';
|
|
5
|
+
import { getSupabaseClient } from './supabaseClient.js';
|
|
6
|
+
import { loadConfig } from './config.js';
|
|
7
|
+
import { blocknoteToMarkdown } from './markdown.js';
|
|
8
|
+
const BUCKET_NAME = 'user-documents';
|
|
9
|
+
/**
|
|
10
|
+
* Get document path in Supabase Storage
|
|
11
|
+
*/
|
|
12
|
+
function getDocumentPath(userId, documentId) {
|
|
13
|
+
return `users/${userId}/documents/${documentId}/latest.json`;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Sanitize filename (remove invalid characters)
|
|
17
|
+
*/
|
|
18
|
+
function sanitizeFilename(filename) {
|
|
19
|
+
return filename
|
|
20
|
+
.replace(/[<>:"/\\|?*]/g, '-') // Replace invalid chars
|
|
21
|
+
.replace(/\s+/g, '-') // Replace spaces with hyphens
|
|
22
|
+
.replace(/-+/g, '-') // Collapse multiple hyphens
|
|
23
|
+
.trim();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Pull all documents from Kaimon and save as markdown files
|
|
27
|
+
* @param flat - If true, save directly to current folder; if false, create KaimonDocs/ subfolder
|
|
28
|
+
*/
|
|
29
|
+
export async function pullDocuments(flat = false) {
|
|
30
|
+
const spinner = ora('Fetching documents from Kaimon...').start();
|
|
31
|
+
try {
|
|
32
|
+
// Get user ID from global config (no project config needed)
|
|
33
|
+
const globalConfig = loadConfig();
|
|
34
|
+
if (!globalConfig.access_token) {
|
|
35
|
+
throw new Error('Not authenticated');
|
|
36
|
+
}
|
|
37
|
+
spinner.stop();
|
|
38
|
+
// Show confirmation before syncing
|
|
39
|
+
const readline = await import('readline');
|
|
40
|
+
const rl = readline.createInterface({
|
|
41
|
+
input: process.stdin,
|
|
42
|
+
output: process.stdout
|
|
43
|
+
});
|
|
44
|
+
const currentFolder = process.cwd();
|
|
45
|
+
const docsDir = flat
|
|
46
|
+
? currentFolder
|
|
47
|
+
: path.join(currentFolder, 'KaimonDocs');
|
|
48
|
+
console.log(chalk.blue('\nš Sync Location'));
|
|
49
|
+
console.log(chalk.gray(` Current folder: ${currentFolder}`));
|
|
50
|
+
console.log(chalk.gray(` Will sync to: ${docsDir}\n`));
|
|
51
|
+
const answer = await new Promise((resolve) => {
|
|
52
|
+
rl.question(chalk.cyan('Continue? (y/N): '), (ans) => {
|
|
53
|
+
rl.close();
|
|
54
|
+
resolve(ans);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
58
|
+
console.log(chalk.yellow('\nā ļø Sync cancelled.\n'));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
spinner.start();
|
|
62
|
+
// Get Supabase client
|
|
63
|
+
const supabase = getSupabaseClient();
|
|
64
|
+
// Fetch all user documents from database
|
|
65
|
+
spinner.text = 'Querying database...';
|
|
66
|
+
const { data: documents, error: dbError } = await supabase
|
|
67
|
+
.from('user_documents')
|
|
68
|
+
.select('*')
|
|
69
|
+
.order('updated_at', { ascending: false });
|
|
70
|
+
if (dbError) {
|
|
71
|
+
throw new Error(`Database error: ${dbError.message}`);
|
|
72
|
+
}
|
|
73
|
+
if (!documents || documents.length === 0) {
|
|
74
|
+
spinner.succeed(chalk.yellow('No documents found in your Kaimon account'));
|
|
75
|
+
console.log(chalk.dim('Create some documents first at kaimon.ai\n'));
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
spinner.text = `Found ${documents.length} document(s), downloading...`;
|
|
79
|
+
// Create docs directory if it doesn't exist
|
|
80
|
+
if (!fs.existsSync(docsDir)) {
|
|
81
|
+
fs.mkdirSync(docsDir, { recursive: true });
|
|
82
|
+
}
|
|
83
|
+
let successCount = 0;
|
|
84
|
+
let errorCount = 0;
|
|
85
|
+
const errors = [];
|
|
86
|
+
// Download each document
|
|
87
|
+
for (const doc of documents) {
|
|
88
|
+
try {
|
|
89
|
+
const documentPath = getDocumentPath(doc.user_id, doc.id);
|
|
90
|
+
// Download from Supabase Storage
|
|
91
|
+
const { data: fileData, error: downloadError } = await supabase.storage
|
|
92
|
+
.from(BUCKET_NAME)
|
|
93
|
+
.download(documentPath);
|
|
94
|
+
if (downloadError) {
|
|
95
|
+
// Handle missing file gracefully
|
|
96
|
+
if (downloadError.message.includes('not found')) {
|
|
97
|
+
spinner.warn(chalk.yellow(`ā ļø Skipping "${doc.title}" - file not found in storage`));
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
throw downloadError;
|
|
101
|
+
}
|
|
102
|
+
// Parse JSON content
|
|
103
|
+
const text = await fileData.text();
|
|
104
|
+
const content = JSON.parse(text);
|
|
105
|
+
// Convert to markdown
|
|
106
|
+
let markdown = '';
|
|
107
|
+
if (content.type === 'blocknote' && Array.isArray(content.content)) {
|
|
108
|
+
markdown = blocknoteToMarkdown(content.content);
|
|
109
|
+
}
|
|
110
|
+
else if (typeof content.content === 'string') {
|
|
111
|
+
markdown = content.content;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
spinner.warn(chalk.yellow(`ā ļø Skipping "${doc.title}" - unsupported format`));
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
// Generate filename
|
|
118
|
+
const filename = sanitizeFilename(doc.title) + '.md';
|
|
119
|
+
const filepath = path.join(docsDir, filename);
|
|
120
|
+
// Add frontmatter with metadata
|
|
121
|
+
const frontmatter = [
|
|
122
|
+
'---',
|
|
123
|
+
`title: "${doc.title}"`,
|
|
124
|
+
`kaimon_id: "${doc.id}"`,
|
|
125
|
+
`created_at: "${doc.created_at}"`,
|
|
126
|
+
`updated_at: "${doc.updated_at}"`,
|
|
127
|
+
'---',
|
|
128
|
+
'',
|
|
129
|
+
markdown
|
|
130
|
+
].join('\n');
|
|
131
|
+
// Write to file
|
|
132
|
+
fs.writeFileSync(filepath, frontmatter, 'utf-8');
|
|
133
|
+
successCount++;
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
errorCount++;
|
|
137
|
+
errors.push(`${doc.title}: ${error.message}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Show results
|
|
141
|
+
const relativeDocsDir = flat ? '.' : './KaimonDocs';
|
|
142
|
+
spinner.succeed(chalk.green(`ā
Downloaded ${successCount} document(s) to ${relativeDocsDir}/`));
|
|
143
|
+
if (errorCount > 0) {
|
|
144
|
+
console.log(chalk.yellow(`\nā ļø ${errorCount} error(s) occurred:`));
|
|
145
|
+
errors.forEach(err => console.log(chalk.dim(` - ${err}`)));
|
|
146
|
+
}
|
|
147
|
+
console.log(chalk.gray(`\nLast synced: ${new Date().toLocaleString()}\n`));
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
spinner.fail(chalk.red('Failed to pull documents'));
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Push local markdown files to Kaimon
|
|
156
|
+
* TODO: Implement in Phase 3
|
|
157
|
+
*/
|
|
158
|
+
export async function pushDocuments() {
|
|
159
|
+
throw new Error('Push functionality not yet implemented');
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Show diff between local and remote
|
|
163
|
+
* TODO: Implement in Phase 3
|
|
164
|
+
*/
|
|
165
|
+
export async function showDiff() {
|
|
166
|
+
throw new Error('Diff functionality not yet implemented');
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=syncOperations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"syncOperations.js","sourceRoot":"","sources":["../../src/utils/syncOperations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD,MAAM,WAAW,GAAG,gBAAgB,CAAC;AAmBrC;;GAEG;AACH,SAAS,eAAe,CAAC,MAAc,EAAE,UAAkB;IACzD,OAAO,SAAS,MAAM,cAAc,UAAU,cAAc,CAAC;AAC/D,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB,CAAC,QAAgB;IACxC,OAAO,QAAQ;SACZ,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,CAAE,wBAAwB;SACvD,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAa,8BAA8B;SAC/D,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAc,4BAA4B;SAC7D,IAAI,EAAE,CAAC;AACZ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAgB,KAAK;IACvD,MAAM,OAAO,GAAG,GAAG,CAAC,mCAAmC,CAAC,CAAC,KAAK,EAAE,CAAC;IAEjE,IAAI,CAAC;QACH,4DAA4D;QAC5D,MAAM,YAAY,GAAG,UAAU,EAAE,CAAC;QAClC,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QAED,OAAO,CAAC,IAAI,EAAE,CAAC;QAEf,mCAAmC;QACnC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;QAC1C,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;YAClC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC;QAEH,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI;YAClB,CAAC,CAAC,aAAa;YACf,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;QAE3C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC;QAC9C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,qBAAqB,aAAa,EAAE,CAAC,CAAC,CAAC;QAC9D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,OAAO,IAAI,CAAC,CAAC,CAAC;QAExD,MAAM,MAAM,GAAG,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,EAAE;YACnD,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE;gBACnD,EAAE,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,CAAC,GAAG,CAAC,CAAC;YACf,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,WAAW,EAAE,KAAK,GAAG,IAAI,MAAM,CAAC,WAAW,EAAE,KAAK,KAAK,EAAE,CAAC;YACnE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC,CAAC;YACrD,OAAO;QACT,CAAC;QAED,OAAO,CAAC,KAAK,EAAE,CAAC;QAEhB,sBAAsB;QACtB,MAAM,QAAQ,GAAG,iBAAiB,EAAE,CAAC;QAErC,yCAAyC;QACzC,OAAO,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACtC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,QAAQ;aACvD,IAAI,CAAC,gBAAgB,CAAC;aACtB,MAAM,CAAC,GAAG,CAAC;aACX,KAAK,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;QAE7C,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,mBAAmB,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QACxD,CAAC;QAED,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,2CAA2C,CAAC,CAAC,CAAC;YAC3E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC,CAAC;YACrE,OAAO;QACT,CAAC;QAED,OAAO,CAAC,IAAI,GAAG,SAAS,SAAS,CAAC,MAAM,8BAA8B,CAAC;QAEvE,4CAA4C;QAC5C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,CAAC;QAED,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,MAAM,MAAM,GAAa,EAAE,CAAC;QAE5B,yBAAyB;QACzB,KAAK,MAAM,GAAG,IAAI,SAA6B,EAAE,CAAC;YAChD,IAAI,CAAC;gBACH,MAAM,YAAY,GAAG,eAAe,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;gBAE1D,iCAAiC;gBACjC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,MAAM,QAAQ,CAAC,OAAO;qBACpE,IAAI,CAAC,WAAW,CAAC;qBACjB,QAAQ,CAAC,YAAY,CAAC,CAAC;gBAE1B,IAAI,aAAa,EAAE,CAAC;oBAClB,iCAAiC;oBACjC,IAAI,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;wBAChD,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,iBAAiB,GAAG,CAAC,KAAK,+BAA+B,CAAC,CAAC,CAAC;wBACtF,SAAS;oBACX,CAAC;oBACD,MAAM,aAAa,CAAC;gBACtB,CAAC;gBAED,qBAAqB;gBACrB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnC,MAAM,OAAO,GAAoB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAElD,sBAAsB;gBACtB,IAAI,QAAQ,GAAG,EAAE,CAAC;gBAClB,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;oBACnE,QAAQ,GAAG,mBAAmB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBAClD,CAAC;qBAAM,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;oBAC/C,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;gBAC7B,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,iBAAiB,GAAG,CAAC,KAAK,wBAAwB,CAAC,CAAC,CAAC;oBAC/E,SAAS;gBACX,CAAC;gBAED,oBAAoB;gBACpB,MAAM,QAAQ,GAAG,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;gBACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;gBAE9C,gCAAgC;gBAChC,MAAM,WAAW,GAAG;oBAClB,KAAK;oBACL,WAAW,GAAG,CAAC,KAAK,GAAG;oBACvB,eAAe,GAAG,CAAC,EAAE,GAAG;oBACxB,gBAAgB,GAAG,CAAC,UAAU,GAAG;oBACjC,gBAAgB,GAAG,CAAC,UAAU,GAAG;oBACjC,KAAK;oBACL,EAAE;oBACF,QAAQ;iBACT,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAEb,gBAAgB;gBAChB,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;gBACjD,YAAY,EAAE,CAAC;YAEjB,CAAC;YAAC,OAAO,KAAU,EAAE,CAAC;gBACpB,UAAU,EAAE,CAAC;gBACb,MAAM,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;QAED,eAAe;QACf,MAAM,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC;QACpD,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,gBAAgB,YAAY,mBAAmB,eAAe,GAAG,CAAC,CAAC,CAAC;QAEhG,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,UAAU,qBAAqB,CAAC,CAAC,CAAC;YACpE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9D,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,kBAAkB,IAAI,IAAI,EAAE,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC,CAAC;IAE7E,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC,CAAC;QACpD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;AAC5D,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;AAC5D,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kaimon-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "CLI tool to sync Kaimon documentation with your codebase",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,23 +23,30 @@
|
|
|
23
23
|
],
|
|
24
24
|
"author": "Kaimon",
|
|
25
25
|
"license": "MIT",
|
|
26
|
+
"files": [
|
|
27
|
+
"bin",
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
],
|
|
26
32
|
"dependencies": {
|
|
27
|
-
"
|
|
33
|
+
"@supabase/supabase-js": "^2.97.0",
|
|
28
34
|
"axios": "^1.7.0",
|
|
29
35
|
"chalk": "^5.3.0",
|
|
30
|
-
"
|
|
31
|
-
"dotenv": "^17.0.0",
|
|
36
|
+
"commander": "^14.0.0",
|
|
32
37
|
"conf": "^15.0.0",
|
|
33
|
-
"
|
|
38
|
+
"dotenv": "^17.0.0",
|
|
39
|
+
"open": "^10.0.0",
|
|
40
|
+
"ora": "^9.0.0"
|
|
34
41
|
},
|
|
35
42
|
"devDependencies": {
|
|
36
43
|
"@types/node": "^25.0.0",
|
|
37
|
-
"typescript": "^5.4.0",
|
|
38
|
-
"ts-node": "^10.9.2",
|
|
39
|
-
"eslint": "^10.0.0",
|
|
40
44
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
41
45
|
"@typescript-eslint/parser": "^8.0.0",
|
|
46
|
+
"eslint": "^10.0.0",
|
|
42
47
|
"prettier": "^3.2.0",
|
|
48
|
+
"ts-node": "^10.9.2",
|
|
49
|
+
"typescript": "^5.4.0",
|
|
43
50
|
"vitest": "^4.0.0"
|
|
44
51
|
},
|
|
45
52
|
"engines": {
|
package/src/commands/auth.ts
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import chalk from 'chalk';
|
|
3
|
-
import open from 'open';
|
|
4
|
-
import { getAuthUrl, CLI_AUTH_PATH } from '../config/constants.js';
|
|
5
|
-
import { loadConfig, saveConfig, clearConfig, isAuthenticated } from '../utils/config.js';
|
|
6
|
-
|
|
7
|
-
// Mask token for display (show first 8 and last 8 characters)
|
|
8
|
-
function maskToken(token: string): string {
|
|
9
|
-
if (!token) return '';
|
|
10
|
-
if (token.length <= 20) return token; // Don't mask if too short
|
|
11
|
-
const start = token.substring(0, 8);
|
|
12
|
-
const end = token.substring(token.length - 8);
|
|
13
|
-
const maskLength = Math.min(token.length - 16, 40); // Max 40 dots
|
|
14
|
-
return `${start}${'ā¢'.repeat(maskLength)}${end}`;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const auth = new Command('auth')
|
|
18
|
-
.description('Authenticate with Kaimon');
|
|
19
|
-
|
|
20
|
-
// Login command
|
|
21
|
-
auth
|
|
22
|
-
.command('login')
|
|
23
|
-
.description('Login to your Kaimon account')
|
|
24
|
-
.option('--dev', 'Use development URL (localhost)')
|
|
25
|
-
.action(async (options) => {
|
|
26
|
-
try {
|
|
27
|
-
console.log(chalk.blue('š Opening browser for authentication...\n'));
|
|
28
|
-
|
|
29
|
-
// Construct auth URL
|
|
30
|
-
const baseUrl = options.dev ? 'http://localhost:5173' : getAuthUrl();
|
|
31
|
-
const authUrl = `${baseUrl}${CLI_AUTH_PATH}`;
|
|
32
|
-
|
|
33
|
-
console.log(chalk.gray(`URL: ${authUrl}\n`));
|
|
34
|
-
|
|
35
|
-
// Open browser
|
|
36
|
-
await open(authUrl);
|
|
37
|
-
|
|
38
|
-
console.log(chalk.yellow('Please complete authentication in your browser.'));
|
|
39
|
-
console.log(chalk.gray('After logging in, copy the access token and paste it here.\n'));
|
|
40
|
-
|
|
41
|
-
// Wait for user to paste token with hidden input
|
|
42
|
-
const readline = await import('readline');
|
|
43
|
-
const rl = readline.createInterface({
|
|
44
|
-
input: process.stdin,
|
|
45
|
-
output: process.stdout
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
// Mute output to hide token input
|
|
49
|
-
const mutableStdout = process.stdout as any;
|
|
50
|
-
console.log(chalk.cyan('Paste your access token below:'));
|
|
51
|
-
console.log(chalk.dim('(Your paste will be invisible for security - press Enter when done)'));
|
|
52
|
-
mutableStdout.write(chalk.cyan('> '));
|
|
53
|
-
|
|
54
|
-
let token = '';
|
|
55
|
-
rl.on('line', (input) => {
|
|
56
|
-
token = input;
|
|
57
|
-
rl.close();
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// Mute the output while typing
|
|
61
|
-
const oldWrite = mutableStdout.write;
|
|
62
|
-
mutableStdout.write = (chunk: string) => {
|
|
63
|
-
// Only show the prompt, hide everything else
|
|
64
|
-
return true;
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
rl.on('close', () => {
|
|
68
|
-
// Restore normal output
|
|
69
|
-
mutableStdout.write = oldWrite;
|
|
70
|
-
|
|
71
|
-
if (!token || token.trim() === '') {
|
|
72
|
-
console.log(chalk.red('\nā No token provided. Authentication cancelled.'));
|
|
73
|
-
process.exit(1);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Show confirmation that token was received
|
|
77
|
-
console.log(chalk.green(`\nā Token received (${token.trim().length} characters)`));
|
|
78
|
-
console.log(chalk.gray('Verifying and saving...\n'));
|
|
79
|
-
|
|
80
|
-
// Save token to config
|
|
81
|
-
saveConfig({
|
|
82
|
-
access_token: token.trim(),
|
|
83
|
-
expires_at: new Date(Date.now() + 60 * 60 * 1000).toISOString() // 1 hour from now
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
console.log(chalk.green('ā
Authentication successful!'));
|
|
87
|
-
console.log(chalk.gray(`Token: ${maskToken(token.trim())}`));
|
|
88
|
-
console.log(chalk.gray('Saved to ~/.kaimon/config.json\n'));
|
|
89
|
-
console.log(chalk.blue('You can now use other CLI commands like:'));
|
|
90
|
-
console.log(chalk.gray(' kaimon sync --pull'));
|
|
91
|
-
console.log(chalk.gray(' kaimon sync --push\n'));
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
} catch (error: any) {
|
|
95
|
-
console.error(chalk.red('ā Login failed:'), error.message);
|
|
96
|
-
process.exit(1);
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
// Logout command
|
|
101
|
-
auth
|
|
102
|
-
.command('logout')
|
|
103
|
-
.description('Logout from Kaimon')
|
|
104
|
-
.action(async () => {
|
|
105
|
-
try {
|
|
106
|
-
if (!isAuthenticated()) {
|
|
107
|
-
console.log(chalk.yellow('ā ļø You are not logged in.'));
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
clearConfig();
|
|
112
|
-
console.log(chalk.green('ā
Logged out successfully!'));
|
|
113
|
-
console.log(chalk.gray('Token removed from ~/.kaimon/config.json\n'));
|
|
114
|
-
} catch (error: any) {
|
|
115
|
-
console.error(chalk.red('ā Logout failed:'), error.message);
|
|
116
|
-
process.exit(1);
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
// Status command
|
|
121
|
-
auth
|
|
122
|
-
.command('status')
|
|
123
|
-
.description('Check authentication status')
|
|
124
|
-
.option('--show-token', 'Show full access token (security risk)')
|
|
125
|
-
.action(async (options) => {
|
|
126
|
-
try {
|
|
127
|
-
const config = loadConfig();
|
|
128
|
-
|
|
129
|
-
if (!config.access_token) {
|
|
130
|
-
console.log(chalk.yellow('ā Not authenticated'));
|
|
131
|
-
console.log(chalk.gray('Run "kaimon auth login" to authenticate\n'));
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
console.log(chalk.green('ā
Authenticated'));
|
|
136
|
-
|
|
137
|
-
if (config.user_email) {
|
|
138
|
-
console.log(chalk.gray(`Email: ${config.user_email}`));
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Show token (masked by default)
|
|
142
|
-
if (options.showToken) {
|
|
143
|
-
console.log(chalk.gray(`Token: ${config.access_token}`));
|
|
144
|
-
console.log(chalk.yellow('ā ļø Full token shown above - keep it secure!'));
|
|
145
|
-
} else {
|
|
146
|
-
console.log(chalk.gray(`Token: ${maskToken(config.access_token)}`));
|
|
147
|
-
console.log(chalk.dim('Use --show-token to reveal full token'));
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (config.expires_at) {
|
|
151
|
-
const expiresAt = new Date(config.expires_at);
|
|
152
|
-
const now = new Date();
|
|
153
|
-
const isExpired = expiresAt < now;
|
|
154
|
-
|
|
155
|
-
if (isExpired) {
|
|
156
|
-
console.log(chalk.red('Status: Expired'));
|
|
157
|
-
console.log(chalk.yellow('Please login again: kaimon auth login\n'));
|
|
158
|
-
} else {
|
|
159
|
-
console.log(chalk.gray(`Expires: ${expiresAt.toLocaleString()}`));
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
console.log(chalk.gray(`Config: ~/.kaimon/config.json\n`));
|
|
164
|
-
} catch (error: any) {
|
|
165
|
-
console.error(chalk.red('ā Status check failed:'), error.message);
|
|
166
|
-
process.exit(1);
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
export { auth };
|