@pedroaugusto04/kb-cli 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/client.js +121 -0
- package/dist/client.js.map +1 -0
- package/dist/commands/ask.js +46 -0
- package/dist/commands/ask.js.map +1 -0
- package/dist/commands/config.js +34 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/init.js +95 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.js +55 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/note.js +113 -0
- package/dist/commands/note.js.map +1 -0
- package/dist/commands/repl.js +96 -0
- package/dist/commands/repl.js.map +1 -0
- package/dist/config.js +98 -0
- package/dist/config.js.map +1 -0
- package/dist/index.js +111 -0
- package/dist/index.js.map +1 -0
- package/package.json +17 -0
package/dist/client.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { loadConfig, saveConfig, clearConfigAuth } from './config.js';
|
|
2
|
+
export class ApiClientError extends Error {
|
|
3
|
+
status;
|
|
4
|
+
body;
|
|
5
|
+
constructor(status, message, body) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.status = status;
|
|
8
|
+
this.body = body;
|
|
9
|
+
this.name = 'ApiClientError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function parseSetCookie(cookieHeaders) {
|
|
13
|
+
const cookies = {};
|
|
14
|
+
for (const header of cookieHeaders) {
|
|
15
|
+
const parts = header.split(';')[0]?.trim().split('=') || [];
|
|
16
|
+
if (parts[0] && parts[1] !== undefined) {
|
|
17
|
+
cookies[parts[0]] = decodeURIComponent(parts[1]);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return cookies;
|
|
21
|
+
}
|
|
22
|
+
export class ApiClient {
|
|
23
|
+
async request(path, options = {}) {
|
|
24
|
+
const config = loadConfig();
|
|
25
|
+
const url = `${config.apiUrl.replace(/\/$/, '')}/${path.replace(/^\//, '')}`;
|
|
26
|
+
const headers = new Headers(options.headers || {});
|
|
27
|
+
if (config.cookies.kb_access_token || config.cookies.kb_refresh_token) {
|
|
28
|
+
const cookieParts = [];
|
|
29
|
+
if (config.cookies.kb_access_token)
|
|
30
|
+
cookieParts.push(`kb_access_token=${config.cookies.kb_access_token}`);
|
|
31
|
+
if (config.cookies.kb_refresh_token)
|
|
32
|
+
cookieParts.push(`kb_refresh_token=${config.cookies.kb_refresh_token}`);
|
|
33
|
+
headers.set('Cookie', cookieParts.join('; '));
|
|
34
|
+
}
|
|
35
|
+
const response = await fetch(url, { ...options, headers });
|
|
36
|
+
// Extract cookies from Set-Cookie headers
|
|
37
|
+
// getSetCookie() is available in Node.js 18+ global fetch Response
|
|
38
|
+
const setCookieHeaders = typeof response.headers.getSetCookie === 'function'
|
|
39
|
+
? response.headers.getSetCookie()
|
|
40
|
+
: [];
|
|
41
|
+
if (setCookieHeaders.length > 0) {
|
|
42
|
+
const newCookies = parseSetCookie(setCookieHeaders);
|
|
43
|
+
saveConfig({ cookies: newCookies });
|
|
44
|
+
}
|
|
45
|
+
return response;
|
|
46
|
+
}
|
|
47
|
+
async fetch(path, options = {}) {
|
|
48
|
+
let response = await this.request(path, options);
|
|
49
|
+
// If unauthorized, attempt token refresh if we have a refresh token
|
|
50
|
+
if (response.status === 401 && !path.includes('auth/login') && !path.includes('auth/refresh')) {
|
|
51
|
+
const config = loadConfig();
|
|
52
|
+
if (config.cookies.kb_refresh_token) {
|
|
53
|
+
try {
|
|
54
|
+
const refreshResponse = await this.request('/api/auth/refresh', { method: 'POST' });
|
|
55
|
+
if (refreshResponse.ok) {
|
|
56
|
+
// Token was refreshed (cookies saved automatically), retry original request
|
|
57
|
+
response = await this.request(path, options);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
clearConfigAuth();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
clearConfigAuth();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (!response.ok) {
|
|
69
|
+
let body;
|
|
70
|
+
try {
|
|
71
|
+
body = await response.json();
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
body = await response.text().catch(() => undefined);
|
|
75
|
+
}
|
|
76
|
+
throw new ApiClientError(response.status, body?.message || `Request failed with status ${response.status}`, body);
|
|
77
|
+
}
|
|
78
|
+
if (response.status === 204) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
return response.json();
|
|
82
|
+
}
|
|
83
|
+
async login(email, password) {
|
|
84
|
+
clearConfigAuth(); // Reset current auth cookies
|
|
85
|
+
return this.fetch('/api/auth/login', {
|
|
86
|
+
method: 'POST',
|
|
87
|
+
headers: { 'Content-Type': 'application/json' },
|
|
88
|
+
body: JSON.stringify({ email, password }),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
async ask(question, projectSlug) {
|
|
92
|
+
return this.fetch('/api/ask', {
|
|
93
|
+
method: 'POST',
|
|
94
|
+
headers: { 'Content-Type': 'application/json' },
|
|
95
|
+
body: JSON.stringify({ question, projectSlug: projectSlug || undefined }),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
async sendAgentMessage(text, media) {
|
|
99
|
+
const config = loadConfig();
|
|
100
|
+
const payload = {
|
|
101
|
+
messageText: text,
|
|
102
|
+
senderId: 'cli-user',
|
|
103
|
+
chatId: 'cli-session',
|
|
104
|
+
hasMedia: !!media,
|
|
105
|
+
media: media || {},
|
|
106
|
+
};
|
|
107
|
+
return this.fetch(`/api/conversation/agent?workspaceSlug=${encodeURIComponent(config.workspaceSlug)}`, {
|
|
108
|
+
method: 'POST',
|
|
109
|
+
headers: { 'Content-Type': 'application/json' },
|
|
110
|
+
body: JSON.stringify(payload),
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
async listProjects() {
|
|
114
|
+
return this.fetch('/api/projects?limit=100');
|
|
115
|
+
}
|
|
116
|
+
async listWorkspaces() {
|
|
117
|
+
return this.fetch('/api/workspaces');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
export const client = new ApiClient();
|
|
121
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +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 url = `${config.apiUrl.replace(/\\/$/, '')}/${path.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 ask(question: string, projectSlug?: string): Promise<any> {\n return this.fetch('/api/ask', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ question, projectSlug: projectSlug || undefined }),\n });\n }\n\n async sendAgentMessage(text: string, media?: { fileName: string; mimeType: string; sizeBytes: number; dataBase64: string }): Promise<any> {\n const config = loadConfig();\n const payload = {\n messageText: text,\n senderId: 'cli-user',\n chatId: 'cli-session',\n hasMedia: !!media,\n media: media || {},\n };\n return this.fetch(`/api/conversation/agent?workspaceSlug=${encodeURIComponent(config.workspaceSlug)}`, {\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"]}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import pc from 'picocolors';
|
|
2
|
+
import { client, ApiClientError } from '../client.js';
|
|
3
|
+
export async function runAsk(question, options) {
|
|
4
|
+
const q = question.trim();
|
|
5
|
+
if (!q) {
|
|
6
|
+
console.error(pc.red('Please provide a question.'));
|
|
7
|
+
process.exit(1);
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
const result = await client.ask(q, options.project);
|
|
11
|
+
if (result && result.answer) {
|
|
12
|
+
console.log('\n' + pc.bold(result.answer) + '\n');
|
|
13
|
+
if (result.confidence !== undefined) {
|
|
14
|
+
let confidenceStr = '';
|
|
15
|
+
if (typeof result.confidence === 'number') {
|
|
16
|
+
confidenceStr = `${Math.round(result.confidence * 100)}%`;
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
confidenceStr = String(result.confidence);
|
|
20
|
+
}
|
|
21
|
+
console.log(pc.gray(`Confidence: ${pc.cyan(confidenceStr)}`));
|
|
22
|
+
}
|
|
23
|
+
if (Array.isArray(result.sources) && result.sources.length > 0) {
|
|
24
|
+
console.log(pc.gray('\nSources:'));
|
|
25
|
+
for (const source of result.sources) {
|
|
26
|
+
const title = source.title || source.fileName || source.path || 'Unnamed Source';
|
|
27
|
+
console.log(pc.gray(` - ${pc.italic(title)}`));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
console.log();
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
console.log(pc.yellow('Could not retrieve an answer. No context available.'));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
if (error instanceof ApiClientError) {
|
|
38
|
+
console.error(pc.red(`Error (${error.status}): ${error.body?.message || error.message}`));
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
console.error(pc.red(`Error: ${error.message || 'Failed to communicate with KB'}`));
|
|
42
|
+
}
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=ask.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ask.js","sourceRoot":"","sources":["../../src/commands/ask.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEtD,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,QAAgB,EAAE,OAA6B;IAC1E,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC1B,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAEpD,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;YAElD,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;gBACpC,IAAI,aAAa,GAAG,EAAE,CAAC;gBACvB,IAAI,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;oBAC1C,aAAa,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,GAAG,GAAG,CAAC,GAAG,CAAC;gBAC5D,CAAC;qBAAM,CAAC;oBACN,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;gBAC5C,CAAC;gBACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC;YAChE,CAAC;YAED,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC/D,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;gBACnC,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;oBACpC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,IAAI,IAAI,gBAAgB,CAAC;oBACjF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;gBACjD,CAAC;YACH,CAAC;YACD,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,qDAAqD,CAAC,CAAC,CAAC;QAChF,CAAC;IACH,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,IAAI,KAAK,YAAY,cAAc,EAAE,CAAC;YACpC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,KAAK,CAAC,MAAM,MAAO,KAAK,CAAC,IAAY,EAAE,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACrG,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,KAAK,CAAC,OAAO,IAAI,+BAA+B,EAAE,CAAC,CAAC,CAAC;QACtF,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC","sourcesContent":["import pc from 'picocolors';\nimport { client, ApiClientError } from '../client.js';\n\nexport async function runAsk(question: string, options: { project?: string }): Promise<void> {\n const q = question.trim();\n if (!q) {\n console.error(pc.red('Please provide a question.'));\n process.exit(1);\n }\n\n try {\n const result = await client.ask(q, options.project);\n\n if (result && result.answer) {\n console.log('\\n' + pc.bold(result.answer) + '\\n');\n\n if (result.confidence !== undefined) {\n let confidenceStr = '';\n if (typeof result.confidence === 'number') {\n confidenceStr = `${Math.round(result.confidence * 100)}%`;\n } else {\n confidenceStr = String(result.confidence);\n }\n console.log(pc.gray(`Confidence: ${pc.cyan(confidenceStr)}`));\n }\n\n if (Array.isArray(result.sources) && result.sources.length > 0) {\n console.log(pc.gray('\\nSources:'));\n for (const source of result.sources) {\n const title = source.title || source.fileName || source.path || 'Unnamed Source';\n console.log(pc.gray(` - ${pc.italic(title)}`));\n }\n }\n console.log();\n } else {\n console.log(pc.yellow('Could not retrieve an answer. No context available.'));\n }\n } catch (error: any) {\n if (error instanceof ApiClientError) {\n console.error(pc.red(`Error (${error.status}): ${(error.body as any)?.message || error.message}`));\n } else {\n console.error(pc.red(`Error: ${error.message || 'Failed to communicate with KB'}`));\n }\n process.exit(1);\n }\n}\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import pc from 'picocolors';
|
|
2
|
+
import { loadConfig, saveConfig } from '../config.js';
|
|
3
|
+
const VALID_KEYS = ['apiUrl', 'workspaceSlug', 'defaultProjectSlug'];
|
|
4
|
+
export function runConfigGet(key) {
|
|
5
|
+
const config = loadConfig();
|
|
6
|
+
if (!VALID_KEYS.includes(key)) {
|
|
7
|
+
console.error(pc.red(`Invalid configuration key. Valid keys are: ${VALID_KEYS.join(', ')}`));
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
const val = config[key];
|
|
11
|
+
console.log(val);
|
|
12
|
+
}
|
|
13
|
+
export function runConfigSet(key, value) {
|
|
14
|
+
if (!VALID_KEYS.includes(key)) {
|
|
15
|
+
console.error(pc.red(`Invalid configuration key. Valid keys are: ${VALID_KEYS.join(', ')}`));
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
let formattedValue = value.trim();
|
|
19
|
+
if (key === 'apiUrl') {
|
|
20
|
+
formattedValue = formattedValue.replace(/\/$/, '');
|
|
21
|
+
}
|
|
22
|
+
saveConfig({ [key]: formattedValue });
|
|
23
|
+
console.log(pc.green(`Updated configuration: ${key} = ${formattedValue}`));
|
|
24
|
+
}
|
|
25
|
+
export function runConfigList() {
|
|
26
|
+
const config = loadConfig();
|
|
27
|
+
console.log(pc.cyan('Current CLI Configuration:'));
|
|
28
|
+
console.log(`${pc.bold('API URL:')} ${config.apiUrl}`);
|
|
29
|
+
console.log(`${pc.bold('Workspace:')} ${config.workspaceSlug}`);
|
|
30
|
+
console.log(`${pc.bold('Default Project:')} ${config.defaultProjectSlug}`);
|
|
31
|
+
const hasAccessToken = !!config.cookies.kb_access_token;
|
|
32
|
+
console.log(`${pc.bold('Authentication Status:')} ${hasAccessToken ? pc.green('Logged In') : pc.red('Not Logged In')}`);
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAItD,MAAM,UAAU,GAAgB,CAAC,QAAQ,EAAE,eAAe,EAAE,oBAAoB,CAAC,CAAC;AAElF,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAgB,CAAC,EAAE,CAAC;QAC3C,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,8CAA8C,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,CAAC,GAAgB,CAAC,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,KAAa;IACrD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAgB,CAAC,EAAE,CAAC;QAC3C,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,8CAA8C,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,cAAc,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAClC,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;QACrB,cAAc,GAAG,cAAc,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC;IACtC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,0BAA0B,GAAG,MAAM,cAAc,EAAE,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC,CAAC;IACnD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;IAChE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,MAAM,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAC3E,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,wBAAwB,CAAC,IAAI,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;AAC1H,CAAC","sourcesContent":["import pc from 'picocolors';\nimport { loadConfig, saveConfig } from '../config.js';\n\ntype ConfigKey = 'apiUrl' | 'workspaceSlug' | 'defaultProjectSlug';\n\nconst VALID_KEYS: ConfigKey[] = ['apiUrl', 'workspaceSlug', 'defaultProjectSlug'];\n\nexport function runConfigGet(key: string): void {\n const config = loadConfig();\n if (!VALID_KEYS.includes(key as ConfigKey)) {\n console.error(pc.red(`Invalid configuration key. Valid keys are: ${VALID_KEYS.join(', ')}`));\n process.exit(1);\n }\n const val = config[key as ConfigKey];\n console.log(val);\n}\n\nexport function runConfigSet(key: string, value: string): void {\n if (!VALID_KEYS.includes(key as ConfigKey)) {\n console.error(pc.red(`Invalid configuration key. Valid keys are: ${VALID_KEYS.join(', ')}`));\n process.exit(1);\n }\n\n let formattedValue = value.trim();\n if (key === 'apiUrl') {\n formattedValue = formattedValue.replace(/\\/$/, '');\n }\n\n saveConfig({ [key]: formattedValue });\n console.log(pc.green(`Updated configuration: ${key} = ${formattedValue}`));\n}\n\nexport function runConfigList(): void {\n const config = loadConfig();\n console.log(pc.cyan('Current CLI Configuration:'));\n console.log(`${pc.bold('API URL:')} ${config.apiUrl}`);\n console.log(`${pc.bold('Workspace:')} ${config.workspaceSlug}`);\n console.log(`${pc.bold('Default Project:')} ${config.defaultProjectSlug}`);\n const hasAccessToken = !!config.cookies.kb_access_token;\n console.log(`${pc.bold('Authentication Status:')} ${hasAccessToken ? pc.green('Logged In') : pc.red('Not Logged In')}`);\n}\n"]}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { intro, outro, text, password, select, spinner, isCancel } from '@clack/prompts';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
import { saveConfig } from '../config.js';
|
|
4
|
+
import { ApiClient } from '../client.js';
|
|
5
|
+
export async function runInit() {
|
|
6
|
+
intro(pc.cyan('Knowledge Base (kb) CLI Setup'));
|
|
7
|
+
const apiUrlInput = await text({
|
|
8
|
+
message: 'Enter your KB API Server URL:',
|
|
9
|
+
placeholder: 'http://localhost:3000',
|
|
10
|
+
initialValue: 'http://localhost:3000',
|
|
11
|
+
validate: (value) => {
|
|
12
|
+
if (!value || !value.trim())
|
|
13
|
+
return 'Server URL cannot be empty';
|
|
14
|
+
if (!value.startsWith('http://') && !value.startsWith('https://')) {
|
|
15
|
+
return 'URL must start with http:// or https://';
|
|
16
|
+
}
|
|
17
|
+
return;
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
if (isCancel(apiUrlInput)) {
|
|
21
|
+
outro(pc.red('Setup cancelled.'));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const apiUrl = apiUrlInput.trim().replace(/\/$/, '');
|
|
25
|
+
const email = await text({
|
|
26
|
+
message: 'Enter your account email:',
|
|
27
|
+
validate: (value) => {
|
|
28
|
+
if (!value || !value.trim())
|
|
29
|
+
return 'Email is required';
|
|
30
|
+
if (!value.includes('@'))
|
|
31
|
+
return 'Enter a valid email address';
|
|
32
|
+
return;
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
if (isCancel(email)) {
|
|
36
|
+
outro(pc.red('Setup cancelled.'));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const userPassword = await password({
|
|
40
|
+
message: 'Enter your password:',
|
|
41
|
+
validate: (value) => {
|
|
42
|
+
if (!value)
|
|
43
|
+
return 'Password is required';
|
|
44
|
+
return;
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
if (isCancel(userPassword)) {
|
|
48
|
+
outro(pc.red('Setup cancelled.'));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const s = spinner();
|
|
52
|
+
s.start('Connecting and authenticating...');
|
|
53
|
+
// Save temporary URL so ApiClient can use it for requests
|
|
54
|
+
saveConfig({ apiUrl });
|
|
55
|
+
const client = new ApiClient();
|
|
56
|
+
try {
|
|
57
|
+
const authResult = await client.login(email.trim(), userPassword);
|
|
58
|
+
s.message('Auth successful! Fetching workspaces...');
|
|
59
|
+
const workspacesResult = await client.listWorkspaces();
|
|
60
|
+
s.stop(pc.green('Authenticated successfully!'));
|
|
61
|
+
let selectedWorkspace = 'default';
|
|
62
|
+
if (workspacesResult && Array.isArray(workspacesResult.workspaces)) {
|
|
63
|
+
const workspaces = workspacesResult.workspaces;
|
|
64
|
+
if (workspaces.length > 1) {
|
|
65
|
+
const workspaceSelection = await select({
|
|
66
|
+
message: 'Select your default workspace:',
|
|
67
|
+
options: workspaces.map((w) => ({
|
|
68
|
+
value: w.workspaceSlug,
|
|
69
|
+
label: w.displayName || w.workspaceSlug,
|
|
70
|
+
})),
|
|
71
|
+
});
|
|
72
|
+
if (isCancel(workspaceSelection)) {
|
|
73
|
+
outro(pc.red('Setup cancelled.'));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
selectedWorkspace = String(workspaceSelection);
|
|
77
|
+
}
|
|
78
|
+
else if (workspaces.length === 1 && workspaces[0]) {
|
|
79
|
+
selectedWorkspace = workspaces[0].workspaceSlug;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
saveConfig({
|
|
83
|
+
apiUrl,
|
|
84
|
+
workspaceSlug: selectedWorkspace,
|
|
85
|
+
defaultProjectSlug: 'inbox',
|
|
86
|
+
});
|
|
87
|
+
outro(pc.green(`Setup complete! CLI initialized and ready in workspace "${selectedWorkspace}".`));
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
s.stop(pc.red('Authentication failed'));
|
|
91
|
+
const errorMsg = error?.body?.message || error?.message || 'Unknown error';
|
|
92
|
+
outro(pc.red(`Error: ${errorMsg}. Please check your credentials and URL, and run 'kb init' again.`));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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","sourcesContent":["import { intro, outro, text, password, select, spinner, isCancel } from '@clack/prompts';\nimport pc from 'picocolors';\nimport { saveConfig } from '../config.js';\nimport { ApiClient } from '../client.js';\n\nexport async function runInit(): Promise<void> {\n intro(pc.cyan('Knowledge Base (kb) CLI Setup'));\n\n const apiUrlInput = await text({\n message: 'Enter your KB API Server URL:',\n placeholder: 'http://localhost:3000',\n initialValue: 'http://localhost:3000',\n validate: (value) => {\n if (!value || !value.trim()) return 'Server URL cannot be empty';\n if (!value.startsWith('http://') && !value.startsWith('https://')) {\n return 'URL must start with http:// or https://';\n }\n return;\n },\n });\n\n if (isCancel(apiUrlInput)) {\n outro(pc.red('Setup cancelled.'));\n return;\n }\n\n const apiUrl = apiUrlInput.trim().replace(/\\/$/, '');\n\n const email = await text({\n message: 'Enter your account email:',\n validate: (value) => {\n if (!value || !value.trim()) return 'Email is required';\n if (!value.includes('@')) return 'Enter a valid email address';\n return;\n },\n });\n\n if (isCancel(email)) {\n outro(pc.red('Setup cancelled.'));\n return;\n }\n\n const userPassword = await password({\n message: 'Enter your password:',\n validate: (value) => {\n if (!value) return 'Password is required';\n return;\n },\n });\n\n if (isCancel(userPassword)) {\n outro(pc.red('Setup cancelled.'));\n return;\n }\n\n const s = spinner();\n s.start('Connecting and authenticating...');\n\n // Save temporary URL so ApiClient can use it for requests\n saveConfig({ apiUrl });\n\n const client = new ApiClient();\n\n try {\n const authResult = await client.login(email.trim(), userPassword);\n s.message('Auth successful! Fetching workspaces...');\n\n const workspacesResult = await client.listWorkspaces();\n s.stop(pc.green('Authenticated successfully!'));\n\n let selectedWorkspace = 'default';\n if (workspacesResult && Array.isArray(workspacesResult.workspaces)) {\n const workspaces = workspacesResult.workspaces;\n if (workspaces.length > 1) {\n const workspaceSelection = await select({\n message: 'Select your default workspace:',\n options: workspaces.map((w: any) => ({\n value: w.workspaceSlug,\n label: w.displayName || w.workspaceSlug,\n })),\n });\n\n if (isCancel(workspaceSelection)) {\n outro(pc.red('Setup cancelled.'));\n return;\n }\n selectedWorkspace = String(workspaceSelection);\n } else if (workspaces.length === 1 && workspaces[0]) {\n selectedWorkspace = workspaces[0].workspaceSlug;\n }\n }\n\n saveConfig({\n apiUrl,\n workspaceSlug: selectedWorkspace,\n defaultProjectSlug: 'inbox',\n });\n\n outro(pc.green(`Setup complete! CLI initialized and ready in workspace \"${selectedWorkspace}\".`));\n } catch (error: any) {\n s.stop(pc.red('Authentication failed'));\n const errorMsg = error?.body?.message || error?.message || 'Unknown error';\n outro(pc.red(`Error: ${errorMsg}. Please check your credentials and URL, and run 'kb init' again.`));\n }\n}\n"]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import pc from 'picocolors';
|
|
2
|
+
import { client, ApiClientError } from '../client.js';
|
|
3
|
+
export async function runListProjects() {
|
|
4
|
+
try {
|
|
5
|
+
const result = await client.listProjects();
|
|
6
|
+
const projects = Array.isArray(result) ? result : result?.projects;
|
|
7
|
+
if (!projects || projects.length === 0) {
|
|
8
|
+
console.log(pc.yellow('No active projects found.'));
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
console.log(pc.cyan('\nActive Projects:'));
|
|
12
|
+
for (const project of projects) {
|
|
13
|
+
const slug = project.projectSlug || 'inbox';
|
|
14
|
+
const name = project.displayName || project.name || slug;
|
|
15
|
+
console.log(` - ${pc.bold(slug)}: ${pc.gray(name)}`);
|
|
16
|
+
}
|
|
17
|
+
console.log();
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
if (error instanceof ApiClientError) {
|
|
21
|
+
console.error(pc.red(`Error (${error.status}): ${error.body?.message || error.message}`));
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
console.error(pc.red(`Error: ${error.message || 'Failed to list projects'}`));
|
|
25
|
+
}
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export async function runListWorkspaces() {
|
|
30
|
+
try {
|
|
31
|
+
const result = await client.listWorkspaces();
|
|
32
|
+
const workspaces = Array.isArray(result) ? result : result?.workspaces;
|
|
33
|
+
if (!workspaces || workspaces.length === 0) {
|
|
34
|
+
console.log(pc.yellow('No workspaces found.'));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
console.log(pc.cyan('\nAvailable Workspaces:'));
|
|
38
|
+
for (const ws of workspaces) {
|
|
39
|
+
const slug = ws.workspaceSlug;
|
|
40
|
+
const name = ws.displayName || slug;
|
|
41
|
+
console.log(` - ${pc.bold(slug)}: ${pc.gray(name)}`);
|
|
42
|
+
}
|
|
43
|
+
console.log();
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (error instanceof ApiClientError) {
|
|
47
|
+
console.error(pc.red(`Error (${error.status}): ${error.body?.message || error.message}`));
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
console.error(pc.red(`Error: ${error.message || 'Failed to list workspaces'}`));
|
|
51
|
+
}
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"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","sourcesContent":["import pc from 'picocolors';\nimport { client, ApiClientError } from '../client.js';\n\nexport async function runListProjects(): Promise<void> {\n try {\n const result = await client.listProjects();\n const projects = Array.isArray(result) ? result : result?.projects;\n\n if (!projects || projects.length === 0) {\n console.log(pc.yellow('No active projects found.'));\n return;\n }\n\n console.log(pc.cyan('\\nActive Projects:'));\n for (const project of projects) {\n const slug = project.projectSlug || 'inbox';\n const name = project.displayName || project.name || slug;\n console.log(` - ${pc.bold(slug)}: ${pc.gray(name)}`);\n }\n console.log();\n } catch (error: any) {\n if (error instanceof ApiClientError) {\n console.error(pc.red(`Error (${error.status}): ${(error.body as any)?.message || error.message}`));\n } else {\n console.error(pc.red(`Error: ${error.message || 'Failed to list projects'}`));\n }\n process.exit(1);\n }\n}\n\nexport async function runListWorkspaces(): Promise<void> {\n try {\n const result = await client.listWorkspaces();\n const workspaces = Array.isArray(result) ? result : result?.workspaces;\n\n if (!workspaces || workspaces.length === 0) {\n console.log(pc.yellow('No workspaces found.'));\n return;\n }\n\n console.log(pc.cyan('\\nAvailable Workspaces:'));\n for (const ws of workspaces) {\n const slug = ws.workspaceSlug;\n const name = ws.displayName || slug;\n console.log(` - ${pc.bold(slug)}: ${pc.gray(name)}`);\n }\n console.log();\n } catch (error: any) {\n if (error instanceof ApiClientError) {\n console.error(pc.red(`Error (${error.status}): ${(error.body as any)?.message || error.message}`));\n } else {\n console.error(pc.red(`Error: ${error.message || 'Failed to list workspaces'}`));\n }\n process.exit(1);\n }\n}\n"]}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import pc from 'picocolors';
|
|
4
|
+
import { text as clackText, isCancel, spinner } from '@clack/prompts';
|
|
5
|
+
import { client, ApiClientError } from '../client.js';
|
|
6
|
+
function getMimeType(filePath) {
|
|
7
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
8
|
+
const map = {
|
|
9
|
+
'.png': 'image/png',
|
|
10
|
+
'.jpg': 'image/jpeg',
|
|
11
|
+
'.jpeg': 'image/jpeg',
|
|
12
|
+
'.webp': 'image/webp',
|
|
13
|
+
'.gif': 'image/gif',
|
|
14
|
+
'.svg': 'image/svg+xml',
|
|
15
|
+
'.pdf': 'application/pdf',
|
|
16
|
+
'.txt': 'text/plain',
|
|
17
|
+
'.md': 'text/markdown',
|
|
18
|
+
'.json': 'application/json',
|
|
19
|
+
'.csv': 'text/csv',
|
|
20
|
+
'.log': 'text/plain',
|
|
21
|
+
'.yaml': 'text/yaml',
|
|
22
|
+
'.yml': 'text/yaml',
|
|
23
|
+
'.xml': 'text/xml',
|
|
24
|
+
'.js': 'application/javascript',
|
|
25
|
+
'.ts': 'application/typescript',
|
|
26
|
+
'.html': 'text/html',
|
|
27
|
+
'.css': 'text/css',
|
|
28
|
+
'.py': 'text/x-python',
|
|
29
|
+
'.sh': 'text/x-shellscript',
|
|
30
|
+
};
|
|
31
|
+
return map[ext] || 'application/octet-stream';
|
|
32
|
+
}
|
|
33
|
+
export async function runNote(noteText, options) {
|
|
34
|
+
let media;
|
|
35
|
+
if (options.file) {
|
|
36
|
+
const filePath = path.resolve(options.file);
|
|
37
|
+
if (!fs.existsSync(filePath)) {
|
|
38
|
+
console.error(pc.red(`Error: File not found at ${options.file}`));
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const stats = fs.statSync(filePath);
|
|
43
|
+
const buffer = fs.readFileSync(filePath);
|
|
44
|
+
media = {
|
|
45
|
+
fileName: path.basename(filePath),
|
|
46
|
+
mimeType: getMimeType(filePath),
|
|
47
|
+
sizeBytes: stats.size,
|
|
48
|
+
dataBase64: buffer.toString('base64'),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
console.error(pc.red(`Error reading file: ${err.message}`));
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const s = spinner();
|
|
57
|
+
s.start('Sending message to agent...');
|
|
58
|
+
try {
|
|
59
|
+
let response = await client.sendAgentMessage(noteText, media);
|
|
60
|
+
// Clear media after first turn so we don't re-upload on subsequent clarification turns
|
|
61
|
+
media = undefined;
|
|
62
|
+
while (response) {
|
|
63
|
+
const action = response.action;
|
|
64
|
+
const replyText = response.replyText || '';
|
|
65
|
+
if (action === 'submit') {
|
|
66
|
+
s.stop(pc.green('Success!'));
|
|
67
|
+
console.log('\n' + pc.cyan(replyText) + '\n');
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
if (action === 'cancel') {
|
|
71
|
+
s.stop(pc.yellow('Cancelled'));
|
|
72
|
+
console.log('\n' + pc.yellow(replyText) + '\n');
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
if (action === 'ask') {
|
|
76
|
+
s.stop(pc.cyan('Clarification needed'));
|
|
77
|
+
console.log('\n' + pc.magenta('🤖 ' + replyText));
|
|
78
|
+
const userReply = await clackText({
|
|
79
|
+
message: 'Your reply:',
|
|
80
|
+
validate: (val) => {
|
|
81
|
+
if (!val || !val.trim())
|
|
82
|
+
return 'Reply cannot be empty. Type "cancel" to abort.';
|
|
83
|
+
return;
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
if (isCancel(userReply)) {
|
|
87
|
+
s.start('Cancelling session...');
|
|
88
|
+
response = await client.sendAgentMessage('cancel');
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
s.start('Sending reply...');
|
|
92
|
+
response = await client.sendAgentMessage(String(userReply));
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
// Fallback for unexpected states
|
|
96
|
+
s.stop(pc.green('Response received'));
|
|
97
|
+
console.log('\n' + replyText + '\n');
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
s.stop(pc.red('Error processing agent conversation'));
|
|
104
|
+
if (error instanceof ApiClientError) {
|
|
105
|
+
console.error(pc.red(`Error (${error.status}): ${error.body?.message || error.message}`));
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
console.error(pc.red(`Error: ${error.message || 'Failed to communicate with agent'}`));
|
|
109
|
+
}
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=note.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"note.js","sourceRoot":"","sources":["../../src/commands/note.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport pc from 'picocolors';\nimport { text as clackText, isCancel, spinner } from '@clack/prompts';\nimport { client, ApiClientError } from '../client.js';\n\nfunction getMimeType(filePath: string): string {\n const ext = path.extname(filePath).toLowerCase();\n const map: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.webp': 'image/webp',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.pdf': 'application/pdf',\n '.txt': 'text/plain',\n '.md': 'text/markdown',\n '.json': 'application/json',\n '.csv': 'text/csv',\n '.log': 'text/plain',\n '.yaml': 'text/yaml',\n '.yml': 'text/yaml',\n '.xml': 'text/xml',\n '.js': 'application/javascript',\n '.ts': 'application/typescript',\n '.html': 'text/html',\n '.css': 'text/css',\n '.py': 'text/x-python',\n '.sh': 'text/x-shellscript',\n };\n return map[ext] || 'application/octet-stream';\n}\n\nexport async function runNote(noteText: string, options: { file?: string }): Promise<void> {\n let media: { fileName: string; mimeType: string; sizeBytes: number; dataBase64: string } | undefined;\n\n if (options.file) {\n const filePath = path.resolve(options.file);\n if (!fs.existsSync(filePath)) {\n console.error(pc.red(`Error: File not found at ${options.file}`));\n process.exit(1);\n }\n try {\n const stats = fs.statSync(filePath);\n const buffer = fs.readFileSync(filePath);\n media = {\n fileName: path.basename(filePath),\n mimeType: getMimeType(filePath),\n sizeBytes: stats.size,\n dataBase64: buffer.toString('base64'),\n };\n } catch (err: any) {\n console.error(pc.red(`Error reading file: ${err.message}`));\n process.exit(1);\n }\n }\n\n const s = spinner();\n s.start('Sending message to agent...');\n\n try {\n let response = await client.sendAgentMessage(noteText, media);\n \n // Clear media after first turn so we don't re-upload on subsequent clarification turns\n media = undefined;\n\n while (response) {\n const action = response.action;\n const replyText = response.replyText || '';\n\n if (action === 'submit') {\n s.stop(pc.green('Success!'));\n console.log('\\n' + pc.cyan(replyText) + '\\n');\n break;\n }\n\n if (action === 'cancel') {\n s.stop(pc.yellow('Cancelled'));\n console.log('\\n' + pc.yellow(replyText) + '\\n');\n break;\n }\n\n if (action === 'ask') {\n s.stop(pc.cyan('Clarification needed'));\n console.log('\\n' + pc.magenta('🤖 ' + replyText));\n\n const userReply = await clackText({\n message: 'Your reply:',\n validate: (val) => {\n if (!val || !val.trim()) return 'Reply cannot be empty. Type \"cancel\" to abort.';\n return;\n },\n });\n\n if (isCancel(userReply)) {\n s.start('Cancelling session...');\n response = await client.sendAgentMessage('cancel');\n continue;\n }\n\n s.start('Sending reply...');\n response = await client.sendAgentMessage(String(userReply));\n } else {\n // Fallback for unexpected states\n s.stop(pc.green('Response received'));\n console.log('\\n' + replyText + '\\n');\n break;\n }\n }\n } catch (error: any) {\n s.stop(pc.red('Error processing agent conversation'));\n if (error instanceof ApiClientError) {\n console.error(pc.red(`Error (${error.status}): ${(error.body as any)?.message || error.message}`));\n } else {\n console.error(pc.red(`Error: ${error.message || 'Failed to communicate with agent'}`));\n }\n process.exit(1);\n }\n}\n"]}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import readline from 'node:readline';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
import { runAsk } from './ask.js';
|
|
4
|
+
import { runNote } from './note.js';
|
|
5
|
+
import { runListProjects, runListWorkspaces } from './list.js';
|
|
6
|
+
import { loadConfig } from '../config.js';
|
|
7
|
+
const COMMANDS = ['/ask ', '/kb ', '/exit', 'projects', 'workspaces', 'help'];
|
|
8
|
+
function completer(line) {
|
|
9
|
+
const hits = COMMANDS.filter((c) => c.startsWith(line.trim()));
|
|
10
|
+
return [hits.length ? hits : COMMANDS, line];
|
|
11
|
+
}
|
|
12
|
+
export function runRepl() {
|
|
13
|
+
const config = loadConfig();
|
|
14
|
+
console.log(pc.cyan('================================================'));
|
|
15
|
+
console.log(pc.cyan(` Knowledge Base Interactive Session (kb REPL) `));
|
|
16
|
+
console.log(pc.cyan(` Active Workspace: ${pc.bold(config.workspaceSlug)}`));
|
|
17
|
+
console.log(pc.cyan(` Type ${pc.bold('/exit')} to quit, ${pc.bold('help')} for command list.`));
|
|
18
|
+
console.log(pc.cyan(` [TAB] to autocomplete commands. `));
|
|
19
|
+
console.log(pc.cyan('================================================\n'));
|
|
20
|
+
const rl = readline.createInterface({
|
|
21
|
+
input: process.stdin,
|
|
22
|
+
output: process.stdout,
|
|
23
|
+
completer,
|
|
24
|
+
});
|
|
25
|
+
rl.setPrompt(pc.magenta('kb> '));
|
|
26
|
+
rl.prompt();
|
|
27
|
+
rl.on('line', async (line) => {
|
|
28
|
+
const trimmed = line.trim();
|
|
29
|
+
if (!trimmed) {
|
|
30
|
+
rl.prompt();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (trimmed === '/exit' || trimmed === 'exit' || trimmed === 'quit') {
|
|
34
|
+
console.log(pc.gray('Goodbye!'));
|
|
35
|
+
rl.close();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (trimmed === 'help') {
|
|
39
|
+
console.log(pc.cyan('\nAvailable Commands:'));
|
|
40
|
+
console.log(` ${pc.bold('/ask <question>')} - Query the knowledge base`);
|
|
41
|
+
console.log(` ${pc.bold('/kb <note>')} - Send a note to the agent`);
|
|
42
|
+
console.log(` ${pc.bold('<any text>')} - Sends text directly to the agent (shortcut for /kb)`);
|
|
43
|
+
console.log(` ${pc.bold('projects')} - List all projects in active workspace`);
|
|
44
|
+
console.log(` ${pc.bold('workspaces')} - List available workspaces`);
|
|
45
|
+
console.log(` ${pc.bold('/exit')} - Exit session\n`);
|
|
46
|
+
rl.prompt();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (trimmed === 'projects') {
|
|
50
|
+
// Temporarily pause readline interface so output does not conflict
|
|
51
|
+
rl.pause();
|
|
52
|
+
await runListProjects();
|
|
53
|
+
rl.resume();
|
|
54
|
+
rl.prompt();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (trimmed === 'workspaces') {
|
|
58
|
+
rl.pause();
|
|
59
|
+
await runListWorkspaces();
|
|
60
|
+
rl.resume();
|
|
61
|
+
rl.prompt();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
// Process Slash Commands
|
|
65
|
+
if (trimmed.startsWith('/ask ')) {
|
|
66
|
+
const question = trimmed.substring(5).trim();
|
|
67
|
+
rl.pause();
|
|
68
|
+
await runAsk(question, {});
|
|
69
|
+
rl.resume();
|
|
70
|
+
rl.prompt();
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (trimmed.startsWith('/kb ')) {
|
|
74
|
+
const note = trimmed.substring(4).trim();
|
|
75
|
+
rl.pause();
|
|
76
|
+
await runNote(note, {});
|
|
77
|
+
rl.resume();
|
|
78
|
+
rl.prompt();
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (trimmed.startsWith('/')) {
|
|
82
|
+
console.log(pc.red(`Unknown command: ${trimmed}. Type 'help' for available commands.`));
|
|
83
|
+
rl.prompt();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
// Default: treat as note text for agent
|
|
87
|
+
rl.pause();
|
|
88
|
+
await runNote(trimmed, {});
|
|
89
|
+
rl.resume();
|
|
90
|
+
rl.prompt();
|
|
91
|
+
});
|
|
92
|
+
rl.on('close', () => {
|
|
93
|
+
process.exit(0);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=repl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repl.js","sourceRoot":"","sources":["../../src/commands/repl.ts"],"names":[],"mappings":"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","sourcesContent":["import readline from 'node:readline';\nimport pc from 'picocolors';\nimport { runAsk } from './ask.js';\nimport { runNote } from './note.js';\nimport { runListProjects, runListWorkspaces } from './list.js';\nimport { loadConfig } from '../config.js';\n\nconst COMMANDS = ['/ask ', '/kb ', '/exit', 'projects', 'workspaces', 'help'];\n\nfunction completer(line: string) {\n const hits = COMMANDS.filter((c) => c.startsWith(line.trim()));\n return [hits.length ? hits : COMMANDS, line];\n}\n\nexport function runRepl(): void {\n const config = loadConfig();\n console.log(pc.cyan('================================================'));\n console.log(pc.cyan(` Knowledge Base Interactive Session (kb REPL) `));\n console.log(pc.cyan(` Active Workspace: ${pc.bold(config.workspaceSlug)}`));\n console.log(pc.cyan(` Type ${pc.bold('/exit')} to quit, ${pc.bold('help')} for command list.`));\n console.log(pc.cyan(` [TAB] to autocomplete commands. `));\n console.log(pc.cyan('================================================\\n'));\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n completer,\n });\n\n rl.setPrompt(pc.magenta('kb> '));\n rl.prompt();\n\n rl.on('line', async (line) => {\n const trimmed = line.trim();\n\n if (!trimmed) {\n rl.prompt();\n return;\n }\n\n if (trimmed === '/exit' || trimmed === 'exit' || trimmed === 'quit') {\n console.log(pc.gray('Goodbye!'));\n rl.close();\n return;\n }\n\n if (trimmed === 'help') {\n console.log(pc.cyan('\\nAvailable Commands:'));\n console.log(` ${pc.bold('/ask <question>')} - Query the knowledge base`);\n console.log(` ${pc.bold('/kb <note>')} - Send a note to the agent`);\n console.log(` ${pc.bold('<any text>')} - Sends text directly to the agent (shortcut for /kb)`);\n console.log(` ${pc.bold('projects')} - List all projects in active workspace`);\n console.log(` ${pc.bold('workspaces')} - List available workspaces`);\n console.log(` ${pc.bold('/exit')} - Exit session\\n`);\n rl.prompt();\n return;\n }\n\n if (trimmed === 'projects') {\n // Temporarily pause readline interface so output does not conflict\n rl.pause();\n await runListProjects();\n rl.resume();\n rl.prompt();\n return;\n }\n\n if (trimmed === 'workspaces') {\n rl.pause();\n await runListWorkspaces();\n rl.resume();\n rl.prompt();\n return;\n }\n\n // Process Slash Commands\n if (trimmed.startsWith('/ask ')) {\n const question = trimmed.substring(5).trim();\n rl.pause();\n await runAsk(question, {});\n rl.resume();\n rl.prompt();\n return;\n }\n\n if (trimmed.startsWith('/kb ')) {\n const note = trimmed.substring(4).trim();\n rl.pause();\n await runNote(note, {});\n rl.resume();\n rl.prompt();\n return;\n }\n\n if (trimmed.startsWith('/')) {\n console.log(pc.red(`Unknown command: ${trimmed}. Type 'help' for available commands.`));\n rl.prompt();\n return;\n }\n\n // Default: treat as note text for agent\n rl.pause();\n await runNote(trimmed, {});\n rl.resume();\n rl.prompt();\n });\n\n rl.on('close', () => {\n process.exit(0);\n });\n}\n"]}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
// Custom .env loader to avoid external dependencies
|
|
5
|
+
function loadEnv() {
|
|
6
|
+
const searchPaths = [
|
|
7
|
+
path.join(process.cwd(), '.env'),
|
|
8
|
+
path.join(process.cwd(), '..', '.env'),
|
|
9
|
+
];
|
|
10
|
+
for (const envPath of searchPaths) {
|
|
11
|
+
if (fs.existsSync(envPath)) {
|
|
12
|
+
try {
|
|
13
|
+
const content = fs.readFileSync(envPath, 'utf8');
|
|
14
|
+
const lines = content.split(/\r?\n/);
|
|
15
|
+
for (const line of lines) {
|
|
16
|
+
const trimmed = line.trim();
|
|
17
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
18
|
+
continue;
|
|
19
|
+
const eqIdx = trimmed.indexOf('=');
|
|
20
|
+
if (eqIdx > 0) {
|
|
21
|
+
const key = trimmed.substring(0, eqIdx).trim();
|
|
22
|
+
let val = trimmed.substring(eqIdx + 1).trim();
|
|
23
|
+
// Remove wrapping quotes if present
|
|
24
|
+
if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
|
|
25
|
+
val = val.substring(1, val.length - 1);
|
|
26
|
+
}
|
|
27
|
+
if (!process.env[key]) {
|
|
28
|
+
process.env[key] = val;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
break; // Stop at first found .env file
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Continue if reading fails
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Load environment variables
|
|
41
|
+
loadEnv();
|
|
42
|
+
const CONFIG_DIR = process.env.KB_CLI_CONFIG_DIR || path.join(os.homedir(), '.config', 'kb');
|
|
43
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
44
|
+
export function loadConfig() {
|
|
45
|
+
const defaults = {
|
|
46
|
+
apiUrl: process.env.KB_API_URL || process.env.KB_API_PUBLIC_BASE_URL || 'http://127.0.0.1:4310',
|
|
47
|
+
workspaceSlug: process.env.KB_CLI_WORKSPACE || 'default',
|
|
48
|
+
defaultProjectSlug: process.env.KB_CLI_PROJECT || 'inbox',
|
|
49
|
+
cookies: {},
|
|
50
|
+
};
|
|
51
|
+
try {
|
|
52
|
+
if (!fs.existsSync(CONFIG_FILE)) {
|
|
53
|
+
return defaults;
|
|
54
|
+
}
|
|
55
|
+
const data = fs.readFileSync(CONFIG_FILE, 'utf8');
|
|
56
|
+
const parsed = JSON.parse(data);
|
|
57
|
+
return {
|
|
58
|
+
...defaults,
|
|
59
|
+
...parsed,
|
|
60
|
+
cookies: parsed.cookies || {},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return defaults;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export function saveConfig(config) {
|
|
68
|
+
try {
|
|
69
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
70
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
71
|
+
}
|
|
72
|
+
const current = loadConfig();
|
|
73
|
+
const updated = {
|
|
74
|
+
...current,
|
|
75
|
+
...config,
|
|
76
|
+
cookies: {
|
|
77
|
+
...current.cookies,
|
|
78
|
+
...(config.cookies || {}),
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(updated, null, 2), 'utf8');
|
|
82
|
+
try {
|
|
83
|
+
fs.chmodSync(CONFIG_FILE, 0o600);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// Ignore failures to chmod on non-POSIX systems
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
console.error('Error saving configuration:', error instanceof Error ? error.message : String(error));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export function clearConfigAuth() {
|
|
94
|
+
const current = loadConfig();
|
|
95
|
+
current.cookies = {};
|
|
96
|
+
saveConfig(current);
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\n\n// Custom .env loader to avoid external dependencies\nfunction loadEnv() {\n const searchPaths = [\n path.join(process.cwd(), '.env'),\n path.join(process.cwd(), '..', '.env'),\n ];\n\n for (const envPath of searchPaths) {\n if (fs.existsSync(envPath)) {\n try {\n const content = fs.readFileSync(envPath, 'utf8');\n const lines = content.split(/\\r?\\n/);\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n \n const eqIdx = trimmed.indexOf('=');\n if (eqIdx > 0) {\n const key = trimmed.substring(0, eqIdx).trim();\n let val = trimmed.substring(eqIdx + 1).trim();\n \n // Remove wrapping quotes if present\n if ((val.startsWith('\"') && val.endsWith('\"')) || (val.startsWith(\"'\") && val.endsWith(\"'\"))) {\n val = val.substring(1, val.length - 1);\n }\n \n if (!process.env[key]) {\n process.env[key] = val;\n }\n }\n }\n break; // Stop at first found .env file\n } catch {\n // Continue if reading fails\n }\n }\n }\n}\n\n// Load environment variables\nloadEnv();\n\nexport interface CliConfig {\n apiUrl: string;\n workspaceSlug: string;\n defaultProjectSlug: string;\n cookies: {\n kb_access_token?: string;\n kb_refresh_token?: string;\n };\n}\n\nconst CONFIG_DIR = process.env.KB_CLI_CONFIG_DIR || path.join(os.homedir(), '.config', 'kb');\nconst CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');\n\nexport function loadConfig(): CliConfig {\n const defaults: CliConfig = {\n apiUrl: process.env.KB_API_URL || process.env.KB_API_PUBLIC_BASE_URL || 'http://127.0.0.1:4310',\n workspaceSlug: process.env.KB_CLI_WORKSPACE || 'default',\n defaultProjectSlug: process.env.KB_CLI_PROJECT || 'inbox',\n cookies: {},\n };\n\n try {\n if (!fs.existsSync(CONFIG_FILE)) {\n return defaults;\n }\n const data = fs.readFileSync(CONFIG_FILE, 'utf8');\n const parsed = JSON.parse(data);\n return {\n ...defaults,\n ...parsed,\n cookies: parsed.cookies || {},\n };\n } catch {\n return defaults;\n }\n}\n\nexport function saveConfig(config: Partial<CliConfig>): void {\n try {\n if (!fs.existsSync(CONFIG_DIR)) {\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\n }\n const current = loadConfig();\n const updated = {\n ...current,\n ...config,\n cookies: {\n ...current.cookies,\n ...(config.cookies || {}),\n },\n };\n fs.writeFileSync(CONFIG_FILE, JSON.stringify(updated, null, 2), 'utf8');\n try {\n fs.chmodSync(CONFIG_FILE, 0o600);\n } catch {\n // Ignore failures to chmod on non-POSIX systems\n }\n } catch (error) {\n console.error('Error saving configuration:', error instanceof Error ? error.message : String(error));\n }\n}\n\nexport function clearConfigAuth(): void {\n const current = loadConfig();\n current.cookies = {};\n saveConfig(current);\n}\n"]}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import pc from 'picocolors';
|
|
4
|
+
import { runInit } from './commands/init.js';
|
|
5
|
+
import { runConfigGet, runConfigSet, runConfigList } from './commands/config.js';
|
|
6
|
+
import { runAsk } from './commands/ask.js';
|
|
7
|
+
import { runNote } from './commands/note.js';
|
|
8
|
+
import { runListProjects, runListWorkspaces } from './commands/list.js';
|
|
9
|
+
import { runRepl } from './commands/repl.js';
|
|
10
|
+
const program = new Command();
|
|
11
|
+
program
|
|
12
|
+
.name('kb')
|
|
13
|
+
.description('Knowledge Base (kb) CLI tool')
|
|
14
|
+
.version('1.0.0');
|
|
15
|
+
// init command
|
|
16
|
+
program
|
|
17
|
+
.command('init')
|
|
18
|
+
.description('Setup and authenticate the CLI with your Knowledge Base server')
|
|
19
|
+
.action(async () => {
|
|
20
|
+
await runInit();
|
|
21
|
+
});
|
|
22
|
+
// config command
|
|
23
|
+
const configCmd = program
|
|
24
|
+
.command('config')
|
|
25
|
+
.description('View or modify CLI configuration');
|
|
26
|
+
configCmd
|
|
27
|
+
.command('get <key>')
|
|
28
|
+
.description('Get a config value (apiUrl, workspaceSlug, defaultProjectSlug)')
|
|
29
|
+
.action((key) => {
|
|
30
|
+
runConfigGet(key);
|
|
31
|
+
});
|
|
32
|
+
configCmd
|
|
33
|
+
.command('set <key> <value>')
|
|
34
|
+
.description('Set a config value')
|
|
35
|
+
.action((key, value) => {
|
|
36
|
+
runConfigSet(key, value);
|
|
37
|
+
});
|
|
38
|
+
configCmd
|
|
39
|
+
.command('list')
|
|
40
|
+
.description('List current config values')
|
|
41
|
+
.action(() => {
|
|
42
|
+
runConfigList();
|
|
43
|
+
});
|
|
44
|
+
// ask command
|
|
45
|
+
program
|
|
46
|
+
.command('ask <question>')
|
|
47
|
+
.description('Query your knowledge base with a question')
|
|
48
|
+
.option('-p, --project <slug>', 'Specify project context')
|
|
49
|
+
.action(async (question, options) => {
|
|
50
|
+
await runAsk(question, options);
|
|
51
|
+
});
|
|
52
|
+
// projects command
|
|
53
|
+
program
|
|
54
|
+
.command('projects')
|
|
55
|
+
.description('List all projects in the active workspace')
|
|
56
|
+
.action(async () => {
|
|
57
|
+
await runListProjects();
|
|
58
|
+
});
|
|
59
|
+
// workspaces command
|
|
60
|
+
program
|
|
61
|
+
.command('workspaces')
|
|
62
|
+
.description('List all workspaces available')
|
|
63
|
+
.action(async () => {
|
|
64
|
+
await runListWorkspaces();
|
|
65
|
+
});
|
|
66
|
+
// catch-all text action for note creation
|
|
67
|
+
program
|
|
68
|
+
.argument('[note-text...]', 'Create a new note with the specified text')
|
|
69
|
+
.option('-f, --file <path>', 'Attach a file to the note')
|
|
70
|
+
.action(async (noteTextParts, options) => {
|
|
71
|
+
const noteText = Array.isArray(noteTextParts) ? noteTextParts.join(' ') : '';
|
|
72
|
+
// Check if stdin has piped data
|
|
73
|
+
const isPiped = !process.stdin.isTTY;
|
|
74
|
+
if (isPiped) {
|
|
75
|
+
let pipedData = '';
|
|
76
|
+
process.stdin.setEncoding('utf8');
|
|
77
|
+
// Read piped data
|
|
78
|
+
for await (const chunk of process.stdin) {
|
|
79
|
+
pipedData += chunk;
|
|
80
|
+
}
|
|
81
|
+
pipedData = pipedData.trim();
|
|
82
|
+
if (pipedData) {
|
|
83
|
+
const combinedText = noteText
|
|
84
|
+
? `${noteText}\n\n${pipedData}`
|
|
85
|
+
: pipedData;
|
|
86
|
+
await runNote(combinedText, options);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (noteText) {
|
|
91
|
+
await runNote(noteText, options);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
// No text and not piped: open REPL
|
|
95
|
+
runRepl();
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
// Handle argument parsing
|
|
99
|
+
async function main() {
|
|
100
|
+
// If run with no arguments at all, default to REPL (unless stdin is piped)
|
|
101
|
+
if (process.argv.length <= 2 && process.stdin.isTTY) {
|
|
102
|
+
runRepl();
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
await program.parseAsync(process.argv);
|
|
106
|
+
}
|
|
107
|
+
main().catch((err) => {
|
|
108
|
+
console.error(pc.red(`Fatal Error: ${err.message}`));
|
|
109
|
+
process.exit(1);
|
|
110
|
+
});
|
|
111
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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';\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// 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 .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 runRepl();\n }\n });\n\n// Handle argument parsing\nasync function main() {\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 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
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pedroaugusto04/kb-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI client for the Knowledge Base AI system",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"kb": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@clack/prompts": "^1.5.0",
|
|
14
|
+
"commander": "^15.0.0",
|
|
15
|
+
"picocolors": "^1.1.1"
|
|
16
|
+
}
|
|
17
|
+
}
|