@pedroaugusto04/kb-cli 1.1.10 → 1.1.11

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/client.js CHANGED
@@ -139,6 +139,20 @@ export class ApiClient {
139
139
  async listWorkspaces() {
140
140
  return this.fetch('/api/workspaces');
141
141
  }
142
+ async createNote(body) {
143
+ return this.fetch('/api/notes', {
144
+ method: 'POST',
145
+ headers: { 'Content-Type': 'application/json' },
146
+ body: JSON.stringify(body),
147
+ });
148
+ }
149
+ async updateNote(id, body) {
150
+ return this.fetch(`/api/notes/${encodeURIComponent(id)}`, {
151
+ method: 'PATCH',
152
+ headers: { 'Content-Type': 'application/json' },
153
+ body: JSON.stringify(body),
154
+ });
155
+ }
142
156
  }
143
157
  export const client = new ApiClient();
144
158
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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","sourcesContent":["import { loadConfig, saveConfig, clearConfigAuth } from './config.js';\n\nexport class ApiClientError extends Error {\n constructor(public status: number, message: string, public body?: unknown) {\n super(message);\n this.name = 'ApiClientError';\n }\n}\n\nfunction parseSetCookie(cookieHeaders: string[]): Record<string, string> {\n const cookies: Record<string, string> = {};\n for (const header of cookieHeaders) {\n const parts = header.split(';')[0]?.trim().split('=') || [];\n if (parts[0] && parts[1] !== undefined) {\n cookies[parts[0]] = decodeURIComponent(parts[1]);\n }\n }\n return cookies;\n}\n\nexport class ApiClient {\n private async request(path: string, options: RequestInit = {}): Promise<Response> {\n const config = loadConfig();\n const apiBase = config.apiUrl.replace(/\\/$/, '');\n let cleanPath = path;\n if (apiBase.endsWith('/api') && path.startsWith('/api')) {\n cleanPath = path.substring(4);\n }\n const url = `${apiBase}/${cleanPath.replace(/^\\//, '')}`;\n\n const headers = new Headers(options.headers || {});\n if (config.cookies.kb_access_token || config.cookies.kb_refresh_token) {\n const cookieParts: string[] = [];\n if (config.cookies.kb_access_token) cookieParts.push(`kb_access_token=${config.cookies.kb_access_token}`);\n if (config.cookies.kb_refresh_token) cookieParts.push(`kb_refresh_token=${config.cookies.kb_refresh_token}`);\n headers.set('Cookie', cookieParts.join('; '));\n }\n\n const response = await fetch(url, { ...options, headers });\n\n // Extract cookies from Set-Cookie headers\n // getSetCookie() is available in Node.js 18+ global fetch Response\n const setCookieHeaders = typeof response.headers.getSetCookie === 'function' \n ? response.headers.getSetCookie() \n : [];\n\n if (setCookieHeaders.length > 0) {\n const newCookies = parseSetCookie(setCookieHeaders);\n saveConfig({ cookies: newCookies });\n }\n\n return response;\n }\n\n async fetch(path: string, options: RequestInit = {}): Promise<any> {\n let response = await this.request(path, options);\n\n // If unauthorized, attempt token refresh if we have a refresh token\n if (response.status === 401 && !path.includes('auth/login') && !path.includes('auth/refresh')) {\n const config = loadConfig();\n if (config.cookies.kb_refresh_token) {\n try {\n const refreshResponse = await this.request('/api/auth/refresh', { method: 'POST' });\n if (refreshResponse.ok) {\n // Token was refreshed (cookies saved automatically), retry original request\n response = await this.request(path, options);\n } else {\n clearConfigAuth();\n }\n } catch {\n clearConfigAuth();\n }\n }\n }\n\n if (!response.ok) {\n let body: any;\n try {\n body = await response.json();\n } catch {\n body = await response.text().catch(() => undefined);\n }\n throw new ApiClientError(\n response.status,\n body?.message || `Request failed with status ${response.status}`,\n body\n );\n }\n\n if (response.status === 204) {\n return null;\n }\n\n return response.json();\n }\n\n async login(email: string, password: string): Promise<any> {\n clearConfigAuth(); // Reset current auth cookies\n return this.fetch('/api/auth/login', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email, password }),\n });\n }\n\n async logout(): Promise<any> {\n try {\n await this.fetch('/api/auth/logout', { method: 'POST' });\n } finally {\n clearConfigAuth();\n }\n }\n\n async ask(question: string, projectSlug?: string): Promise<any> {\n const config = loadConfig();\n return this.fetch('/api/ask', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n question,\n projectSlug: projectSlug || undefined,\n workspaceSlug: config.workspaceSlug || undefined,\n }),\n });\n }\n\n async sendAgentMessage(\n text: string,\n media?: { fileName: string; mimeType: string; sizeBytes: number; dataBase64: string },\n projectSlug?: string\n ): Promise<any> {\n const config = loadConfig();\n const activeProject = projectSlug || config.defaultProjectSlug;\n const payload = {\n messageText: text,\n senderId: 'cli-user',\n chatId: 'cli-session',\n hasMedia: !!media,\n media: media || {},\n };\n let url = `/api/conversation/agent?workspaceSlug=${encodeURIComponent(config.workspaceSlug)}`;\n if (activeProject) {\n url += `&projectSlug=${encodeURIComponent(activeProject)}`;\n }\n return this.fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n });\n }\n\n async listProjects(): Promise<any> {\n return this.fetch('/api/projects?limit=100');\n }\n\n async listWorkspaces(): Promise<any> {\n return this.fetch('/api/workspaces');\n }\n}\n\nexport const client = new ApiClient();\n"]}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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","sourcesContent":["import { loadConfig, saveConfig, clearConfigAuth } from './config.js';\n\nexport class ApiClientError extends Error {\n constructor(public status: number, message: string, public body?: unknown) {\n super(message);\n this.name = 'ApiClientError';\n }\n}\n\nfunction parseSetCookie(cookieHeaders: string[]): Record<string, string> {\n const cookies: Record<string, string> = {};\n for (const header of cookieHeaders) {\n const parts = header.split(';')[0]?.trim().split('=') || [];\n if (parts[0] && parts[1] !== undefined) {\n cookies[parts[0]] = decodeURIComponent(parts[1]);\n }\n }\n return cookies;\n}\n\nexport class ApiClient {\n private async request(path: string, options: RequestInit = {}): Promise<Response> {\n const config = loadConfig();\n const apiBase = config.apiUrl.replace(/\\/$/, '');\n let cleanPath = path;\n if (apiBase.endsWith('/api') && path.startsWith('/api')) {\n cleanPath = path.substring(4);\n }\n const url = `${apiBase}/${cleanPath.replace(/^\\//, '')}`;\n\n const headers = new Headers(options.headers || {});\n if (config.cookies.kb_access_token || config.cookies.kb_refresh_token) {\n const cookieParts: string[] = [];\n if (config.cookies.kb_access_token) cookieParts.push(`kb_access_token=${config.cookies.kb_access_token}`);\n if (config.cookies.kb_refresh_token) cookieParts.push(`kb_refresh_token=${config.cookies.kb_refresh_token}`);\n headers.set('Cookie', cookieParts.join('; '));\n }\n\n const response = await fetch(url, { ...options, headers });\n\n // Extract cookies from Set-Cookie headers\n // getSetCookie() is available in Node.js 18+ global fetch Response\n const setCookieHeaders = typeof response.headers.getSetCookie === 'function' \n ? response.headers.getSetCookie() \n : [];\n\n if (setCookieHeaders.length > 0) {\n const newCookies = parseSetCookie(setCookieHeaders);\n saveConfig({ cookies: newCookies });\n }\n\n return response;\n }\n\n async fetch(path: string, options: RequestInit = {}): Promise<any> {\n let response = await this.request(path, options);\n\n // If unauthorized, attempt token refresh if we have a refresh token\n if (response.status === 401 && !path.includes('auth/login') && !path.includes('auth/refresh')) {\n const config = loadConfig();\n if (config.cookies.kb_refresh_token) {\n try {\n const refreshResponse = await this.request('/api/auth/refresh', { method: 'POST' });\n if (refreshResponse.ok) {\n // Token was refreshed (cookies saved automatically), retry original request\n response = await this.request(path, options);\n } else {\n clearConfigAuth();\n }\n } catch {\n clearConfigAuth();\n }\n }\n }\n\n if (!response.ok) {\n let body: any;\n try {\n body = await response.json();\n } catch {\n body = await response.text().catch(() => undefined);\n }\n throw new ApiClientError(\n response.status,\n body?.message || `Request failed with status ${response.status}`,\n body\n );\n }\n\n if (response.status === 204) {\n return null;\n }\n\n return response.json();\n }\n\n async login(email: string, password: string): Promise<any> {\n clearConfigAuth(); // Reset current auth cookies\n return this.fetch('/api/auth/login', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email, password }),\n });\n }\n\n async logout(): Promise<any> {\n try {\n await this.fetch('/api/auth/logout', { method: 'POST' });\n } finally {\n clearConfigAuth();\n }\n }\n\n async ask(question: string, projectSlug?: string): Promise<any> {\n const config = loadConfig();\n return this.fetch('/api/ask', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n question,\n projectSlug: projectSlug || undefined,\n workspaceSlug: config.workspaceSlug || undefined,\n }),\n });\n }\n\n async sendAgentMessage(\n text: string,\n media?: { fileName: string; mimeType: string; sizeBytes: number; dataBase64: string },\n projectSlug?: string\n ): Promise<any> {\n const config = loadConfig();\n const activeProject = projectSlug || config.defaultProjectSlug;\n const payload = {\n messageText: text,\n senderId: 'cli-user',\n chatId: 'cli-session',\n hasMedia: !!media,\n media: media || {},\n };\n let url = `/api/conversation/agent?workspaceSlug=${encodeURIComponent(config.workspaceSlug)}`;\n if (activeProject) {\n url += `&projectSlug=${encodeURIComponent(activeProject)}`;\n }\n return this.fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n });\n }\n\n async listProjects(): Promise<any> {\n return this.fetch('/api/projects?limit=100');\n }\n\n async listWorkspaces(): Promise<any> {\n return this.fetch('/api/workspaces');\n }\n\n async createNote(body: any): Promise<any> {\n return this.fetch('/api/notes', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n }\n\n async updateNote(id: string, body: any): Promise<any> {\n return this.fetch(`/api/notes/${encodeURIComponent(id)}`, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n }\n}\n\nexport const client = new ApiClient();\n\n"]}
@@ -0,0 +1,253 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import crypto from 'node:crypto';
4
+ import pc from 'picocolors';
5
+ import { spinner, outro } from '@clack/prompts';
6
+ import { client, ApiClientError } from '../client.js';
7
+ import { loadConfig } from '../config.js';
8
+ export async function runSync(options) {
9
+ const targetDir = path.resolve(options.dir);
10
+ if (!fs.existsSync(targetDir) || !fs.statSync(targetDir).isDirectory()) {
11
+ console.error(pc.red(`Error: Directory not found at ${options.dir}`));
12
+ process.exit(1);
13
+ }
14
+ const config = loadConfig();
15
+ const defaultProject = options.project || config.defaultProjectSlug || 'inbox';
16
+ const ledgerPath = path.join(targetDir, '.kb-sync.json');
17
+ if (options.dryRun) {
18
+ console.log(pc.yellow('Running in DRY-RUN mode. No changes will be written or sent to the server.'));
19
+ }
20
+ if (options.watch) {
21
+ console.log(pc.cyan(`Starting sync in WATCH mode for directory: ${targetDir}`));
22
+ await syncDirectory(targetDir, defaultProject, ledgerPath, options.dryRun || false);
23
+ // Watch logic
24
+ let debounceTimer = null;
25
+ fs.watch(targetDir, { recursive: true }, (eventType, filename) => {
26
+ if (!filename || filename.endsWith('.kb-sync.json') || !filename.endsWith('.md'))
27
+ return;
28
+ if (debounceTimer)
29
+ clearTimeout(debounceTimer);
30
+ debounceTimer = setTimeout(async () => {
31
+ console.log(pc.blue(`\nChange detected in ${filename}. Syncing...`));
32
+ try {
33
+ await syncDirectory(targetDir, defaultProject, ledgerPath, options.dryRun || false);
34
+ }
35
+ catch (err) {
36
+ console.error(pc.red(`Watch sync failed: ${err.message}`));
37
+ }
38
+ }, 500);
39
+ });
40
+ // Keep process alive in watch mode
41
+ await new Promise(() => { });
42
+ return;
43
+ }
44
+ const s = spinner();
45
+ s.start('Synchronizing files...');
46
+ try {
47
+ const stats = await syncDirectory(targetDir, defaultProject, ledgerPath, options.dryRun || false);
48
+ s.stop(pc.green('Sync complete!'));
49
+ console.log('\n' + pc.bold('Sync Summary:'));
50
+ console.log(` - Created: ${pc.green(stats.created)}`);
51
+ console.log(` - Updated: ${pc.cyan(stats.updated)}`);
52
+ console.log(` - Skipped: ${pc.gray(stats.skipped)}`);
53
+ console.log(` - Failed: ${pc.red(stats.failed)}\n`);
54
+ outro(pc.green('Files synced successfully.'));
55
+ }
56
+ catch (error) {
57
+ s.stop(pc.red('Sync failed'));
58
+ console.error(pc.red(`Error: ${error.message || 'Failed to sync folder.'}`));
59
+ process.exit(1);
60
+ }
61
+ }
62
+ async function syncDirectory(targetDir, defaultProject, ledgerPath, dryRun) {
63
+ const ledger = loadLedger(ledgerPath);
64
+ const files = getMarkdownFiles(targetDir);
65
+ const stats = { created: 0, updated: 0, skipped: 0, failed: 0 };
66
+ const updatedLedgerFiles = {};
67
+ for (const filePath of files) {
68
+ // Relative path to use as key in ledger
69
+ const relativePath = path.relative(targetDir, filePath).replace(/\\/g, '/');
70
+ if (relativePath === '.kb-sync.json')
71
+ continue;
72
+ try {
73
+ const content = fs.readFileSync(filePath, 'utf8');
74
+ const sha256 = calculateSha256(content);
75
+ const mtime = fs.statSync(filePath).mtime.toISOString();
76
+ const filename = path.basename(filePath, '.md');
77
+ const parsed = parseMarkdown(content, filename);
78
+ const targetProject = parsed.projectSlug || defaultProject;
79
+ // Determine Note ID
80
+ let noteId = parsed.id || ledger.files[relativePath]?.noteId;
81
+ // Check if we need to sync
82
+ const ledgerEntry = ledger.files[relativePath];
83
+ if (ledgerEntry && ledgerEntry.sha256 === sha256 && noteId === ledgerEntry.noteId) {
84
+ stats.skipped++;
85
+ updatedLedgerFiles[relativePath] = ledgerEntry;
86
+ continue;
87
+ }
88
+ if (dryRun) {
89
+ if (noteId) {
90
+ console.log(pc.cyan(`[Dry-run] Would UPDATE note ${noteId} (${relativePath})`));
91
+ stats.updated++;
92
+ }
93
+ else {
94
+ console.log(pc.green(`[Dry-run] Would CREATE note for ${relativePath}`));
95
+ stats.created++;
96
+ }
97
+ continue;
98
+ }
99
+ // Sync payload
100
+ const notePayload = {
101
+ title: parsed.title,
102
+ rawText: parsed.body,
103
+ projectSlug: targetProject,
104
+ tags: parsed.tags || [],
105
+ status: parsed.status || 'active',
106
+ canonicalType: parsed.canonicalType || 'note',
107
+ };
108
+ if (noteId) {
109
+ // Update existing note
110
+ try {
111
+ await client.updateNote(noteId, notePayload);
112
+ stats.updated++;
113
+ console.log(pc.cyan(`Updated: ${relativePath}`));
114
+ }
115
+ catch (err) {
116
+ if (err instanceof ApiClientError && err.status === 404) {
117
+ // Note was deleted remotely, treat as new creation
118
+ console.log(pc.yellow(`Note ${noteId} not found on server. Re-creating: ${relativePath}`));
119
+ noteId = undefined;
120
+ }
121
+ else {
122
+ throw err;
123
+ }
124
+ }
125
+ }
126
+ if (!noteId) {
127
+ // Create new note
128
+ const res = await client.createNote(notePayload);
129
+ const createdId = res.noteId || res.id;
130
+ if (!createdId) {
131
+ throw new Error('Failed to retrieve note ID from server response');
132
+ }
133
+ noteId = createdId;
134
+ stats.created++;
135
+ console.log(pc.green(`Created: ${relativePath}`));
136
+ // Inject ID back to frontmatter
137
+ injectIdIntoFrontmatter(filePath, content, noteId);
138
+ }
139
+ // Record in ledger
140
+ updatedLedgerFiles[relativePath] = {
141
+ noteId: noteId,
142
+ sha256: calculateSha256(fs.readFileSync(filePath, 'utf8')), // recalculate in case we injected id
143
+ lastModified: mtime,
144
+ };
145
+ }
146
+ catch (err) {
147
+ stats.failed++;
148
+ console.error(pc.red(`Failed to sync ${relativePath}: ${err.message}`));
149
+ }
150
+ }
151
+ if (!dryRun) {
152
+ saveLedger(ledgerPath, {
153
+ lastSyncedAt: new Date().toISOString(),
154
+ files: {
155
+ ...ledger.files,
156
+ ...updatedLedgerFiles,
157
+ },
158
+ });
159
+ }
160
+ return stats;
161
+ }
162
+ function getMarkdownFiles(dir) {
163
+ let results = [];
164
+ const list = fs.readdirSync(dir);
165
+ for (const file of list) {
166
+ if (file.startsWith('.'))
167
+ continue; // skip hidden dirs/files
168
+ const filePath = path.join(dir, file);
169
+ const stat = fs.statSync(filePath);
170
+ if (stat && stat.isDirectory()) {
171
+ results = results.concat(getMarkdownFiles(filePath));
172
+ }
173
+ else if (file.endsWith('.md')) {
174
+ results.push(filePath);
175
+ }
176
+ }
177
+ return results;
178
+ }
179
+ function calculateSha256(content) {
180
+ return crypto.createHash('sha256').update(content, 'utf8').digest('hex');
181
+ }
182
+ function loadLedger(ledgerPath) {
183
+ const defaults = {
184
+ lastSyncedAt: '',
185
+ files: {},
186
+ };
187
+ try {
188
+ if (!fs.existsSync(ledgerPath))
189
+ return defaults;
190
+ const data = fs.readFileSync(ledgerPath, 'utf8');
191
+ return JSON.parse(data);
192
+ }
193
+ catch {
194
+ return defaults;
195
+ }
196
+ }
197
+ function saveLedger(ledgerPath, ledger) {
198
+ try {
199
+ fs.writeFileSync(ledgerPath, JSON.stringify(ledger, null, 2), 'utf8');
200
+ }
201
+ catch (err) {
202
+ console.error(pc.red(`Error saving sync ledger: ${err.message}`));
203
+ }
204
+ }
205
+ function parseMarkdown(content, fallbackTitle) {
206
+ const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---/;
207
+ const match = content.match(frontmatterRegex);
208
+ if (!match) {
209
+ return { body: content.trim(), title: fallbackTitle };
210
+ }
211
+ const yaml = match[1];
212
+ const body = content.replace(frontmatterRegex, '').trim();
213
+ const metadata = {};
214
+ for (const line of yaml.split('\n')) {
215
+ const colonIdx = line.indexOf(':');
216
+ if (colonIdx > 0) {
217
+ const key = line.substring(0, colonIdx).trim();
218
+ const val = line.substring(colonIdx + 1).trim();
219
+ metadata[key] = val.replace(/^['"]|['"]$/g, '');
220
+ }
221
+ }
222
+ return {
223
+ id: metadata.id || undefined,
224
+ title: metadata.title || fallbackTitle,
225
+ projectSlug: metadata.project || undefined,
226
+ tags: metadata.tags ? metadata.tags.split(',').map(t => t.trim()).filter(Boolean) : undefined,
227
+ canonicalType: metadata.canonicalType || undefined,
228
+ status: metadata.status || undefined,
229
+ body,
230
+ };
231
+ }
232
+ function injectIdIntoFrontmatter(filePath, content, id) {
233
+ const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---/;
234
+ const match = content.match(frontmatterRegex);
235
+ if (match) {
236
+ const yaml = match[1];
237
+ if (yaml.includes('id:')) {
238
+ const updatedYaml = yaml.replace(/id:\s*[^\r\n]*/, `id: ${id}`);
239
+ const updatedContent = content.replace(frontmatterRegex, `---\n${updatedYaml}\n---`);
240
+ fs.writeFileSync(filePath, updatedContent, 'utf8');
241
+ }
242
+ else {
243
+ const updatedYaml = `id: ${id}\n${yaml}`;
244
+ const updatedContent = content.replace(frontmatterRegex, `---\n${updatedYaml}\n---`);
245
+ fs.writeFileSync(filePath, updatedContent, 'utf8');
246
+ }
247
+ }
248
+ else {
249
+ const updatedContent = `---\nid: ${id}\n---\n${content}`;
250
+ fs.writeFileSync(filePath, updatedContent, 'utf8');
251
+ }
252
+ }
253
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport crypto from 'node:crypto';\nimport pc from 'picocolors';\nimport { spinner, outro } from '@clack/prompts';\nimport { client, ApiClientError } from '../client.js';\nimport { loadConfig } from '../config.js';\n\nexport interface SyncOptions {\n dir: string;\n project?: string;\n dryRun?: boolean;\n watch?: boolean;\n}\n\ninterface LedgerEntry {\n noteId: string;\n sha256: string;\n lastModified: string;\n}\n\ninterface SyncLedger {\n lastSyncedAt: string;\n files: Record<string, LedgerEntry>;\n}\n\nexport async function runSync(options: SyncOptions): Promise<void> {\n const targetDir = path.resolve(options.dir);\n if (!fs.existsSync(targetDir) || !fs.statSync(targetDir).isDirectory()) {\n console.error(pc.red(`Error: Directory not found at ${options.dir}`));\n process.exit(1);\n }\n\n const config = loadConfig();\n const defaultProject = options.project || config.defaultProjectSlug || 'inbox';\n const ledgerPath = path.join(targetDir, '.kb-sync.json');\n\n if (options.dryRun) {\n console.log(pc.yellow('Running in DRY-RUN mode. No changes will be written or sent to the server.'));\n }\n\n if (options.watch) {\n console.log(pc.cyan(`Starting sync in WATCH mode for directory: ${targetDir}`));\n await syncDirectory(targetDir, defaultProject, ledgerPath, options.dryRun || false);\n \n // Watch logic\n let debounceTimer: NodeJS.Timeout | null = null;\n fs.watch(targetDir, { recursive: true }, (eventType, filename) => {\n if (!filename || filename.endsWith('.kb-sync.json') || !filename.endsWith('.md')) return;\n \n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(async () => {\n console.log(pc.blue(`\\nChange detected in ${filename}. Syncing...`));\n try {\n await syncDirectory(targetDir, defaultProject, ledgerPath, options.dryRun || false);\n } catch (err: any) {\n console.error(pc.red(`Watch sync failed: ${err.message}`));\n }\n }, 500);\n });\n \n // Keep process alive in watch mode\n await new Promise(() => {});\n return;\n }\n\n const s = spinner();\n s.start('Synchronizing files...');\n\n try {\n const stats = await syncDirectory(targetDir, defaultProject, ledgerPath, options.dryRun || false);\n s.stop(pc.green('Sync complete!'));\n \n console.log('\\n' + pc.bold('Sync Summary:'));\n console.log(` - Created: ${pc.green(stats.created)}`);\n console.log(` - Updated: ${pc.cyan(stats.updated)}`);\n console.log(` - Skipped: ${pc.gray(stats.skipped)}`);\n console.log(` - Failed: ${pc.red(stats.failed)}\\n`);\n \n outro(pc.green('Files synced successfully.'));\n } catch (error: any) {\n s.stop(pc.red('Sync failed'));\n console.error(pc.red(`Error: ${error.message || 'Failed to sync folder.'}`));\n process.exit(1);\n }\n}\n\nasync function syncDirectory(\n targetDir: string,\n defaultProject: string,\n ledgerPath: string,\n dryRun: boolean\n) {\n const ledger = loadLedger(ledgerPath);\n const files = getMarkdownFiles(targetDir);\n \n const stats = { created: 0, updated: 0, skipped: 0, failed: 0 };\n const updatedLedgerFiles: Record<string, LedgerEntry> = {};\n\n for (const filePath of files) {\n // Relative path to use as key in ledger\n const relativePath = path.relative(targetDir, filePath).replace(/\\\\/g, '/');\n if (relativePath === '.kb-sync.json') continue;\n\n try {\n const content = fs.readFileSync(filePath, 'utf8');\n const sha256 = calculateSha256(content);\n const mtime = fs.statSync(filePath).mtime.toISOString();\n const filename = path.basename(filePath, '.md');\n\n const parsed = parseMarkdown(content, filename);\n const targetProject = parsed.projectSlug || defaultProject;\n\n // Determine Note ID\n let noteId: string | undefined = parsed.id || ledger.files[relativePath]?.noteId;\n\n // Check if we need to sync\n const ledgerEntry = ledger.files[relativePath];\n if (ledgerEntry && ledgerEntry.sha256 === sha256 && noteId === ledgerEntry.noteId) {\n stats.skipped++;\n updatedLedgerFiles[relativePath] = ledgerEntry;\n continue;\n }\n\n if (dryRun) {\n if (noteId) {\n console.log(pc.cyan(`[Dry-run] Would UPDATE note ${noteId} (${relativePath})`));\n stats.updated++;\n } else {\n console.log(pc.green(`[Dry-run] Would CREATE note for ${relativePath}`));\n stats.created++;\n }\n continue;\n }\n\n // Sync payload\n const notePayload = {\n title: parsed.title,\n rawText: parsed.body,\n projectSlug: targetProject,\n tags: parsed.tags || [],\n status: parsed.status || 'active',\n canonicalType: parsed.canonicalType || 'note',\n };\n\n if (noteId) {\n // Update existing note\n try {\n await client.updateNote(noteId, notePayload);\n stats.updated++;\n console.log(pc.cyan(`Updated: ${relativePath}`));\n } catch (err: any) {\n if (err instanceof ApiClientError && err.status === 404) {\n // Note was deleted remotely, treat as new creation\n console.log(pc.yellow(`Note ${noteId} not found on server. Re-creating: ${relativePath}`));\n noteId = undefined;\n } else {\n throw err;\n }\n }\n }\n\n if (!noteId) {\n // Create new note\n const res = await client.createNote(notePayload);\n const createdId = res.noteId || res.id;\n if (!createdId) {\n throw new Error('Failed to retrieve note ID from server response');\n }\n noteId = createdId;\n stats.created++;\n console.log(pc.green(`Created: ${relativePath}`));\n \n // Inject ID back to frontmatter\n injectIdIntoFrontmatter(filePath, content, noteId as string);\n }\n\n // Record in ledger\n updatedLedgerFiles[relativePath] = {\n noteId: noteId as string,\n sha256: calculateSha256(fs.readFileSync(filePath, 'utf8')), // recalculate in case we injected id\n lastModified: mtime,\n };\n\n } catch (err: any) {\n stats.failed++;\n console.error(pc.red(`Failed to sync ${relativePath}: ${err.message}`));\n }\n }\n\n if (!dryRun) {\n saveLedger(ledgerPath, {\n lastSyncedAt: new Date().toISOString(),\n files: {\n ...ledger.files,\n ...updatedLedgerFiles,\n },\n });\n }\n\n return stats;\n}\n\nfunction getMarkdownFiles(dir: string): string[] {\n let results: string[] = [];\n const list = fs.readdirSync(dir);\n for (const file of list) {\n if (file.startsWith('.')) continue; // skip hidden dirs/files\n const filePath = path.join(dir, file);\n const stat = fs.statSync(filePath);\n if (stat && stat.isDirectory()) {\n results = results.concat(getMarkdownFiles(filePath));\n } else if (file.endsWith('.md')) {\n results.push(filePath);\n }\n }\n return results;\n}\n\nfunction calculateSha256(content: string): string {\n return crypto.createHash('sha256').update(content, 'utf8').digest('hex');\n}\n\nfunction loadLedger(ledgerPath: string): SyncLedger {\n const defaults: SyncLedger = {\n lastSyncedAt: '',\n files: {},\n };\n try {\n if (!fs.existsSync(ledgerPath)) return defaults;\n const data = fs.readFileSync(ledgerPath, 'utf8');\n return JSON.parse(data) as SyncLedger;\n } catch {\n return defaults;\n }\n}\n\nfunction saveLedger(ledgerPath: string, ledger: SyncLedger): void {\n try {\n fs.writeFileSync(ledgerPath, JSON.stringify(ledger, null, 2), 'utf8');\n } catch (err: any) {\n console.error(pc.red(`Error saving sync ledger: ${err.message}`));\n }\n}\n\ninterface ParsedMarkdown {\n id?: string;\n title?: string;\n projectSlug?: string;\n tags?: string[];\n canonicalType?: string;\n status?: string;\n body: string;\n}\n\nfunction parseMarkdown(content: string, fallbackTitle: string): ParsedMarkdown {\n const frontmatterRegex = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---/;\n const match = content.match(frontmatterRegex);\n if (!match) {\n return { body: content.trim(), title: fallbackTitle };\n }\n const yaml = match[1];\n const body = content.replace(frontmatterRegex, '').trim();\n const metadata: Record<string, string> = {};\n for (const line of yaml.split('\\n')) {\n const colonIdx = line.indexOf(':');\n if (colonIdx > 0) {\n const key = line.substring(0, colonIdx).trim();\n const val = line.substring(colonIdx + 1).trim();\n metadata[key] = val.replace(/^['\"]|['\"]$/g, '');\n }\n }\n return {\n id: metadata.id || undefined,\n title: metadata.title || fallbackTitle,\n projectSlug: metadata.project || undefined,\n tags: metadata.tags ? metadata.tags.split(',').map(t => t.trim()).filter(Boolean) : undefined,\n canonicalType: metadata.canonicalType || undefined,\n status: metadata.status || undefined,\n body,\n };\n}\n\nfunction injectIdIntoFrontmatter(filePath: string, content: string, id: string): void {\n const frontmatterRegex = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---/;\n const match = content.match(frontmatterRegex);\n if (match) {\n const yaml = match[1];\n if (yaml.includes('id:')) {\n const updatedYaml = yaml.replace(/id:\\s*[^\\r\\n]*/, `id: ${id}`);\n const updatedContent = content.replace(frontmatterRegex, `---\\n${updatedYaml}\\n---`);\n fs.writeFileSync(filePath, updatedContent, 'utf8');\n } else {\n const updatedYaml = `id: ${id}\\n${yaml}`;\n const updatedContent = content.replace(frontmatterRegex, `---\\n${updatedYaml}\\n---`);\n fs.writeFileSync(filePath, updatedContent, 'utf8');\n }\n } else {\n const updatedContent = `---\\nid: ${id}\\n---\\n${content}`;\n fs.writeFileSync(filePath, updatedContent, 'utf8');\n }\n}\n"]}
package/dist/index.js CHANGED
@@ -8,6 +8,7 @@ import { runNote } from './commands/note.js';
8
8
  import { runListProjects, runListWorkspaces } from './commands/list.js';
9
9
  import { runRepl } from './commands/repl.js';
10
10
  import { runLogout } from './commands/logout.js';
11
+ import { runSync } from './commands/sync.js';
11
12
  import { loadConfig } from './config.js';
12
13
  const program = new Command();
13
14
  program
@@ -72,6 +73,17 @@ program
72
73
  .action(async () => {
73
74
  await runListWorkspaces();
74
75
  });
76
+ // sync command
77
+ program
78
+ .command('sync')
79
+ .description('Sync a local directory of markdown files with the knowledge base')
80
+ .requiredOption('-d, --dir <path>', 'Path to local directory')
81
+ .option('-p, --project <slug>', 'Default project slug')
82
+ .option('--dry-run', 'Analyze changes without uploading')
83
+ .option('-w, --watch', 'Watch directory for real-time changes')
84
+ .action(async (options) => {
85
+ await runSync(options);
86
+ });
75
87
  // catch-all text action for note creation
76
88
  program
77
89
  .argument('[note-text...]', 'Create a new note with the specified text')
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport pc from 'picocolors';\nimport { runInit } from './commands/init.js';\nimport { runConfigGet, runConfigSet, runConfigList } from './commands/config.js';\nimport { runAsk } from './commands/ask.js';\nimport { runNote } from './commands/note.js';\nimport { runListProjects, runListWorkspaces } from './commands/list.js';\nimport { runRepl } from './commands/repl.js';\nimport { runLogout } from './commands/logout.js';\nimport { loadConfig } from './config.js';\n\nconst program = new Command();\n\nprogram\n .name('kb')\n .description('Knowledge Base (kb) CLI tool')\n .version('1.0.0');\n\n// init command\nprogram\n .command('init')\n .description('Setup and authenticate the CLI with your Knowledge Base server')\n .action(async () => {\n await runInit();\n });\n\n// logout command\nprogram\n .command('logout')\n .description('Log out of your Knowledge Base account and clear local session')\n .action(async () => {\n await runLogout();\n });\n\n// config command\nconst configCmd = program\n .command('config')\n .description('View or modify CLI configuration');\n\nconfigCmd\n .command('get <key>')\n .description('Get a config value (apiUrl, workspaceSlug, defaultProjectSlug)')\n .action((key) => {\n runConfigGet(key);\n });\n\nconfigCmd\n .command('set <key> <value>')\n .description('Set a config value')\n .action((key, value) => {\n runConfigSet(key, value);\n });\n\nconfigCmd\n .command('list')\n .description('List current config values')\n .action(() => {\n runConfigList();\n });\n\n// ask command\nprogram\n .command('ask <question>')\n .description('Query your knowledge base with a question')\n .option('-p, --project <slug>', 'Specify project context')\n .action(async (question, options) => {\n await runAsk(question, options);\n });\n\n// projects command\nprogram\n .command('projects')\n .description('List all projects in the active workspace')\n .action(async () => {\n await runListProjects();\n });\n\n// workspaces command\nprogram\n .command('workspaces')\n .description('List all workspaces available')\n .action(async () => {\n await runListWorkspaces();\n });\n\n// catch-all text action for note creation\nprogram\n .argument('[note-text...]', 'Create a new note with the specified text')\n .option('-f, --file <path>', 'Attach a file to the note')\n .option('-p, --project <slug>', 'Specify project context')\n .action(async (noteTextParts, options) => {\n const noteText = Array.isArray(noteTextParts) ? noteTextParts.join(' ') : '';\n \n // Check if stdin has piped data\n const isPiped = !process.stdin.isTTY;\n\n if (isPiped) {\n let pipedData = '';\n process.stdin.setEncoding('utf8');\n \n // Read piped data\n for await (const chunk of process.stdin) {\n pipedData += chunk;\n }\n\n pipedData = pipedData.trim();\n\n if (pipedData) {\n const combinedText = noteText \n ? `${noteText}\\n\\n${pipedData}`\n : pipedData;\n await runNote(combinedText, options);\n return;\n }\n }\n\n if (noteText) {\n await runNote(noteText, options);\n } else {\n // No text and not piped: open REPL\n await runRepl();\n }\n });\n\nasync function checkAuth() {\n const config = loadConfig();\n if (!config.cookies?.kb_access_token) {\n console.log(pc.yellow('No active session found. You must log in first to use the CLI.'));\n await runInit();\n const newConfig = loadConfig();\n if (!newConfig.cookies?.kb_access_token) {\n console.error(pc.red('Authentication required. Exiting.'));\n process.exit(1);\n }\n }\n}\n\n// Handle argument parsing\nasync function main() {\n const firstArg = process.argv[2];\n \n // Skip auth check for init, logout, config, help, or version requests\n if (\n firstArg !== 'init' && \n firstArg !== 'logout' && \n firstArg !== 'config' && \n firstArg !== '--help' && \n firstArg !== '-h' && \n firstArg !== 'help' && \n firstArg !== '--version' && \n firstArg !== '-V'\n ) {\n await checkAuth();\n }\n\n // If run with no arguments at all, default to REPL (unless stdin is piped)\n if (process.argv.length <= 2 && process.stdin.isTTY) {\n await runRepl();\n return;\n }\n \n await program.parseAsync(process.argv);\n}\n\nmain().catch((err) => {\n console.error(pc.red(`Fatal Error: ${err.message}`));\n process.exit(1);\n});\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,IAAI,CAAC;KACV,WAAW,CAAC,8BAA8B,CAAC;KAC3C,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,eAAe;AACf,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,gEAAgE,CAAC;KAC7E,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,OAAO,EAAE,CAAC;AAClB,CAAC,CAAC,CAAC;AAEL,iBAAiB;AACjB,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,gEAAgE,CAAC;KAC7E,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,SAAS,EAAE,CAAC;AACpB,CAAC,CAAC,CAAC;AAEL,iBAAiB;AACjB,MAAM,SAAS,GAAG,OAAO;KACtB,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,kCAAkC,CAAC,CAAC;AAEnD,SAAS;KACN,OAAO,CAAC,WAAW,CAAC;KACpB,WAAW,CAAC,gEAAgE,CAAC;KAC7E,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE;IACd,YAAY,CAAC,GAAG,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC;AAEL,SAAS;KACN,OAAO,CAAC,mBAAmB,CAAC;KAC5B,WAAW,CAAC,oBAAoB,CAAC;KACjC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;IACrB,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AAC3B,CAAC,CAAC,CAAC;AAEL,SAAS;KACN,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,4BAA4B,CAAC;KACzC,MAAM,CAAC,GAAG,EAAE;IACX,aAAa,EAAE,CAAC;AAClB,CAAC,CAAC,CAAC;AAEL,cAAc;AACd,OAAO;KACJ,OAAO,CAAC,gBAAgB,CAAC;KACzB,WAAW,CAAC,2CAA2C,CAAC;KACxD,MAAM,CAAC,sBAAsB,EAAE,yBAAyB,CAAC;KACzD,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE;IAClC,MAAM,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AAClC,CAAC,CAAC,CAAC;AAEL,mBAAmB;AACnB,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,2CAA2C,CAAC;KACxD,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,eAAe,EAAE,CAAC;AAC1B,CAAC,CAAC,CAAC;AAEL,qBAAqB;AACrB,OAAO;KACJ,OAAO,CAAC,YAAY,CAAC;KACrB,WAAW,CAAC,+BAA+B,CAAC;KAC5C,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,iBAAiB,EAAE,CAAC;AAC5B,CAAC,CAAC,CAAC;AAEL,eAAe;AACf,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,kEAAkE,CAAC;KAC/E,cAAc,CAAC,kBAAkB,EAAE,yBAAyB,CAAC;KAC7D,MAAM,CAAC,sBAAsB,EAAE,sBAAsB,CAAC;KACtD,MAAM,CAAC,WAAW,EAAE,mCAAmC,CAAC;KACxD,MAAM,CAAC,aAAa,EAAE,uCAAuC,CAAC;KAC9D,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;AACzB,CAAC,CAAC,CAAC;AAGL,0CAA0C;AAC1C,OAAO;KACJ,QAAQ,CAAC,gBAAgB,EAAE,2CAA2C,CAAC;KACvE,MAAM,CAAC,mBAAmB,EAAE,2BAA2B,CAAC;KACxD,MAAM,CAAC,sBAAsB,EAAE,yBAAyB,CAAC;KACzD,MAAM,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,EAAE;IACvC,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE7E,gCAAgC;IAChC,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;IAErC,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,SAAS,GAAG,EAAE,CAAC;QACnB,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAElC,kBAAkB;QAClB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YACxC,SAAS,IAAI,KAAK,CAAC;QACrB,CAAC;QAED,SAAS,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;QAE7B,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,YAAY,GAAG,QAAQ;gBAC3B,CAAC,CAAC,GAAG,QAAQ,OAAO,SAAS,EAAE;gBAC/B,CAAC,CAAC,SAAS,CAAC;YACd,MAAM,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACrC,OAAO;QACT,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACnC,CAAC;SAAM,CAAC;QACN,mCAAmC;QACnC,MAAM,OAAO,EAAE,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,KAAK,UAAU,SAAS;IACtB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,eAAe,EAAE,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,gEAAgE,CAAC,CAAC,CAAC;QACzF,MAAM,OAAO,EAAE,CAAC;QAChB,MAAM,SAAS,GAAG,UAAU,EAAE,CAAC;QAC/B,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,eAAe,EAAE,CAAC;YACxC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC,CAAC;YAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;AACH,CAAC;AAED,0BAA0B;AAC1B,KAAK,UAAU,IAAI;IACjB,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAEjC,sEAAsE;IACtE,IACE,QAAQ,KAAK,MAAM;QACnB,QAAQ,KAAK,QAAQ;QACrB,QAAQ,KAAK,QAAQ;QACrB,QAAQ,KAAK,QAAQ;QACrB,QAAQ,KAAK,IAAI;QACjB,QAAQ,KAAK,MAAM;QACnB,QAAQ,KAAK,WAAW;QACxB,QAAQ,KAAK,IAAI,EACjB,CAAC;QACD,MAAM,SAAS,EAAE,CAAC;IACpB,CAAC;IAED,2EAA2E;IAC3E,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACpD,MAAM,OAAO,EAAE,CAAC;QAChB,OAAO;IACT,CAAC;IAED,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,gBAAgB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC","sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport pc from 'picocolors';\nimport { runInit } from './commands/init.js';\nimport { runConfigGet, runConfigSet, runConfigList } from './commands/config.js';\nimport { runAsk } from './commands/ask.js';\nimport { runNote } from './commands/note.js';\nimport { runListProjects, runListWorkspaces } from './commands/list.js';\nimport { runRepl } from './commands/repl.js';\nimport { runLogout } from './commands/logout.js';\nimport { runSync } from './commands/sync.js';\nimport { loadConfig } from './config.js';\n\nconst program = new Command();\n\nprogram\n .name('kb')\n .description('Knowledge Base (kb) CLI tool')\n .version('1.0.0');\n\n// init command\nprogram\n .command('init')\n .description('Setup and authenticate the CLI with your Knowledge Base server')\n .action(async () => {\n await runInit();\n });\n\n// logout command\nprogram\n .command('logout')\n .description('Log out of your Knowledge Base account and clear local session')\n .action(async () => {\n await runLogout();\n });\n\n// config command\nconst configCmd = program\n .command('config')\n .description('View or modify CLI configuration');\n\nconfigCmd\n .command('get <key>')\n .description('Get a config value (apiUrl, workspaceSlug, defaultProjectSlug)')\n .action((key) => {\n runConfigGet(key);\n });\n\nconfigCmd\n .command('set <key> <value>')\n .description('Set a config value')\n .action((key, value) => {\n runConfigSet(key, value);\n });\n\nconfigCmd\n .command('list')\n .description('List current config values')\n .action(() => {\n runConfigList();\n });\n\n// ask command\nprogram\n .command('ask <question>')\n .description('Query your knowledge base with a question')\n .option('-p, --project <slug>', 'Specify project context')\n .action(async (question, options) => {\n await runAsk(question, options);\n });\n\n// projects command\nprogram\n .command('projects')\n .description('List all projects in the active workspace')\n .action(async () => {\n await runListProjects();\n });\n\n// workspaces command\nprogram\n .command('workspaces')\n .description('List all workspaces available')\n .action(async () => {\n await runListWorkspaces();\n });\n\n// sync command\nprogram\n .command('sync')\n .description('Sync a local directory of markdown files with the knowledge base')\n .requiredOption('-d, --dir <path>', 'Path to local directory')\n .option('-p, --project <slug>', 'Default project slug')\n .option('--dry-run', 'Analyze changes without uploading')\n .option('-w, --watch', 'Watch directory for real-time changes')\n .action(async (options) => {\n await runSync(options);\n });\n\n\n// catch-all text action for note creation\nprogram\n .argument('[note-text...]', 'Create a new note with the specified text')\n .option('-f, --file <path>', 'Attach a file to the note')\n .option('-p, --project <slug>', 'Specify project context')\n .action(async (noteTextParts, options) => {\n const noteText = Array.isArray(noteTextParts) ? noteTextParts.join(' ') : '';\n \n // Check if stdin has piped data\n const isPiped = !process.stdin.isTTY;\n\n if (isPiped) {\n let pipedData = '';\n process.stdin.setEncoding('utf8');\n \n // Read piped data\n for await (const chunk of process.stdin) {\n pipedData += chunk;\n }\n\n pipedData = pipedData.trim();\n\n if (pipedData) {\n const combinedText = noteText \n ? `${noteText}\\n\\n${pipedData}`\n : pipedData;\n await runNote(combinedText, options);\n return;\n }\n }\n\n if (noteText) {\n await runNote(noteText, options);\n } else {\n // No text and not piped: open REPL\n await runRepl();\n }\n });\n\nasync function checkAuth() {\n const config = loadConfig();\n if (!config.cookies?.kb_access_token) {\n console.log(pc.yellow('No active session found. You must log in first to use the CLI.'));\n await runInit();\n const newConfig = loadConfig();\n if (!newConfig.cookies?.kb_access_token) {\n console.error(pc.red('Authentication required. Exiting.'));\n process.exit(1);\n }\n }\n}\n\n// Handle argument parsing\nasync function main() {\n const firstArg = process.argv[2];\n \n // Skip auth check for init, logout, config, help, or version requests\n if (\n firstArg !== 'init' && \n firstArg !== 'logout' && \n firstArg !== 'config' && \n firstArg !== '--help' && \n firstArg !== '-h' && \n firstArg !== 'help' && \n firstArg !== '--version' && \n firstArg !== '-V'\n ) {\n await checkAuth();\n }\n\n // If run with no arguments at all, default to REPL (unless stdin is piped)\n if (process.argv.length <= 2 && process.stdin.isTTY) {\n await runRepl();\n return;\n }\n \n await program.parseAsync(process.argv);\n}\n\nmain().catch((err) => {\n console.error(pc.red(`Fatal Error: ${err.message}`));\n process.exit(1);\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pedroaugusto04/kb-cli",
3
- "version": "1.1.10",
3
+ "version": "1.1.11",
4
4
  "description": "CLI client for the Knowledge Base AI system",
5
5
  "type": "module",
6
6
  "bin": {