@chanl-ai/cli 2.0.1
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/bin/chanl.js +10 -0
- package/dist/__tests__/cli.test.d.ts +2 -0
- package/dist/__tests__/cli.test.js +2313 -0
- package/dist/__tests__/cli.test.js.map +1 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.js +72 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/agents.d.ts +8 -0
- package/dist/commands/agents.js +671 -0
- package/dist/commands/agents.js.map +1 -0
- package/dist/commands/auth.d.ts +16 -0
- package/dist/commands/auth.js +294 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/call.d.ts +8 -0
- package/dist/commands/call.js +166 -0
- package/dist/commands/call.js.map +1 -0
- package/dist/commands/calls.d.ts +8 -0
- package/dist/commands/calls.js +719 -0
- package/dist/commands/calls.js.map +1 -0
- package/dist/commands/chat.d.ts +8 -0
- package/dist/commands/chat.js +203 -0
- package/dist/commands/chat.js.map +1 -0
- package/dist/commands/config.d.ts +8 -0
- package/dist/commands/config.js +231 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/health.d.ts +8 -0
- package/dist/commands/health.js +55 -0
- package/dist/commands/health.js.map +1 -0
- package/dist/commands/index.d.ts +18 -0
- package/dist/commands/index.js +39 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/knowledge.d.ts +8 -0
- package/dist/commands/knowledge.js +539 -0
- package/dist/commands/knowledge.js.map +1 -0
- package/dist/commands/mcp.d.ts +8 -0
- package/dist/commands/mcp.js +589 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/memory.d.ts +8 -0
- package/dist/commands/memory.js +408 -0
- package/dist/commands/memory.js.map +1 -0
- package/dist/commands/personas.d.ts +8 -0
- package/dist/commands/personas.js +356 -0
- package/dist/commands/personas.js.map +1 -0
- package/dist/commands/prompts.d.ts +8 -0
- package/dist/commands/prompts.js +295 -0
- package/dist/commands/prompts.js.map +1 -0
- package/dist/commands/scenarios.d.ts +8 -0
- package/dist/commands/scenarios.js +591 -0
- package/dist/commands/scenarios.js.map +1 -0
- package/dist/commands/scorecards.d.ts +8 -0
- package/dist/commands/scorecards.js +570 -0
- package/dist/commands/scorecards.js.map +1 -0
- package/dist/commands/tools.d.ts +8 -0
- package/dist/commands/tools.js +632 -0
- package/dist/commands/tools.js.map +1 -0
- package/dist/commands/toolsets.d.ts +8 -0
- package/dist/commands/toolsets.js +464 -0
- package/dist/commands/toolsets.js.map +1 -0
- package/dist/commands/workspaces.d.ts +8 -0
- package/dist/commands/workspaces.js +170 -0
- package/dist/commands/workspaces.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/config-store.d.ts +117 -0
- package/dist/utils/config-store.js +191 -0
- package/dist/utils/config-store.js.map +1 -0
- package/dist/utils/interactive.d.ts +41 -0
- package/dist/utils/interactive.js +83 -0
- package/dist/utils/interactive.js.map +1 -0
- package/dist/utils/output.d.ts +100 -0
- package/dist/utils/output.js +221 -0
- package/dist/utils/output.js.map +1 -0
- package/dist/utils/sdk-factory.d.ts +15 -0
- package/dist/utils/sdk-factory.js +34 -0
- package/dist/utils/sdk-factory.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { ChanlSDK } from "@chanl-ai/sdk";
|
|
5
|
+
import { configStore } from "../utils/config-store.js";
|
|
6
|
+
import {
|
|
7
|
+
printSuccess,
|
|
8
|
+
printError,
|
|
9
|
+
printBlank,
|
|
10
|
+
isJsonOutput,
|
|
11
|
+
printJson
|
|
12
|
+
} from "../utils/output.js";
|
|
13
|
+
function createHealthCommand() {
|
|
14
|
+
const health = new Command("health").description("Check API health status").action(handleHealth);
|
|
15
|
+
return health;
|
|
16
|
+
}
|
|
17
|
+
async function handleHealth() {
|
|
18
|
+
const baseUrl = configStore.getBaseUrl();
|
|
19
|
+
const sdk = new ChanlSDK({ baseUrl });
|
|
20
|
+
const spinner = ora("Checking API health...").start();
|
|
21
|
+
try {
|
|
22
|
+
const response = await sdk.health.getHealth();
|
|
23
|
+
spinner.stop();
|
|
24
|
+
if (!response.success || !response.data) {
|
|
25
|
+
printError("API health check failed", response.message);
|
|
26
|
+
process.exitCode = 1;
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (isJsonOutput()) {
|
|
30
|
+
printJson(response.data);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
printBlank();
|
|
34
|
+
console.log(chalk.bold("API Health Status:"));
|
|
35
|
+
console.log(` Status: ${response.data.status === "healthy" ? chalk.green("\u2713 healthy") : chalk.red("\u2717 unhealthy")}`);
|
|
36
|
+
console.log(` API URL: ${baseUrl}`);
|
|
37
|
+
if (response.data.version) {
|
|
38
|
+
console.log(` Version: ${response.data.version}`);
|
|
39
|
+
}
|
|
40
|
+
if (response.data.uptime) {
|
|
41
|
+
console.log(` Uptime: ${Math.floor(response.data.uptime / 60)} min`);
|
|
42
|
+
}
|
|
43
|
+
printBlank();
|
|
44
|
+
printSuccess("API is healthy");
|
|
45
|
+
} catch (error) {
|
|
46
|
+
spinner.fail("Health check failed");
|
|
47
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
48
|
+
printError("Error", message);
|
|
49
|
+
process.exitCode = 1;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
createHealthCommand
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/commands/health.ts"],"sourcesContent":["import { Command } from 'commander';\nimport ora from 'ora';\nimport chalk from 'chalk';\nimport { ChanlSDK } from '@chanl-ai/sdk';\nimport { configStore } from '../utils/config-store.js';\nimport {\n printSuccess,\n printError,\n printBlank,\n isJsonOutput,\n printJson,\n} from '../utils/output.js';\n\n/**\n * Create the health command\n */\nexport function createHealthCommand(): Command {\n const health = new Command('health')\n .description('Check API health status')\n .action(handleHealth);\n\n return health;\n}\n\n/**\n * Handle health command\n */\nasync function handleHealth(): Promise<void> {\n const baseUrl = configStore.getBaseUrl();\n const sdk = new ChanlSDK({ baseUrl });\n\n const spinner = ora('Checking API health...').start();\n\n try {\n const response = await sdk.health.getHealth();\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('API health check failed', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n printBlank();\n console.log(chalk.bold('API Health Status:'));\n console.log(` Status: ${response.data.status === 'healthy' ? chalk.green('✓ healthy') : chalk.red('✗ unhealthy')}`);\n console.log(` API URL: ${baseUrl}`);\n if (response.data.version) {\n console.log(` Version: ${response.data.version}`);\n }\n if (response.data.uptime) {\n console.log(` Uptime: ${Math.floor(response.data.uptime / 60)} min`);\n }\n printBlank();\n printSuccess('API is healthy');\n } catch (error) {\n spinner.fail('Health check failed');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n"],"mappings":"AAAA,SAAS,eAAe;AACxB,OAAO,SAAS;AAChB,OAAO,WAAW;AAClB,SAAS,gBAAgB;AACzB,SAAS,mBAAmB;AAC5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAKA,SAAS,sBAA+B;AAC7C,QAAM,SAAS,IAAI,QAAQ,QAAQ,EAChC,YAAY,yBAAyB,EACrC,OAAO,YAAY;AAEtB,SAAO;AACT;AAKA,eAAe,eAA8B;AAC3C,QAAM,UAAU,YAAY,WAAW;AACvC,QAAM,MAAM,IAAI,SAAS,EAAE,QAAQ,CAAC;AAEpC,QAAM,UAAU,IAAI,wBAAwB,EAAE,MAAM;AAEpD,MAAI;AACF,UAAM,WAAW,MAAM,IAAI,OAAO,UAAU;AAE5C,YAAQ,KAAK;AAEb,QAAI,CAAC,SAAS,WAAW,CAAC,SAAS,MAAM;AACvC,iBAAW,2BAA2B,SAAS,OAAO;AACtD,cAAQ,WAAW;AACnB;AAAA,IACF;AAEA,QAAI,aAAa,GAAG;AAClB,gBAAU,SAAS,IAAI;AACvB;AAAA,IACF;AAEA,eAAW;AACX,YAAQ,IAAI,MAAM,KAAK,oBAAoB,CAAC;AAC5C,YAAQ,IAAI,eAAe,SAAS,KAAK,WAAW,YAAY,MAAM,MAAM,gBAAW,IAAI,MAAM,IAAI,kBAAa,CAAC,EAAE;AACrH,YAAQ,IAAI,eAAe,OAAO,EAAE;AACpC,QAAI,SAAS,KAAK,SAAS;AACzB,cAAQ,IAAI,eAAe,SAAS,KAAK,OAAO,EAAE;AAAA,IACpD;AACA,QAAI,SAAS,KAAK,QAAQ;AACxB,cAAQ,IAAI,eAAe,KAAK,MAAM,SAAS,KAAK,SAAS,EAAE,CAAC,MAAM;AAAA,IACxE;AACA,eAAW;AACX,iBAAa,gBAAgB;AAAA,EAC/B,SAAS,OAAO;AACd,YAAQ,KAAK,qBAAqB;AAClC,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,eAAW,SAAS,OAAO;AAC3B,YAAQ,WAAW;AAAA,EACrB;AACF;","names":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { createAuthCommand, createLoginCommand, createLogoutCommand } from './auth.js';
|
|
2
|
+
export { createConfigCommand } from './config.js';
|
|
3
|
+
export { createToolsCommand } from './tools.js';
|
|
4
|
+
export { createToolsetsCommand } from './toolsets.js';
|
|
5
|
+
export { createScenariosCommand } from './scenarios.js';
|
|
6
|
+
export { createCallCommand } from './call.js';
|
|
7
|
+
export { createCallsCommand } from './calls.js';
|
|
8
|
+
export { createPersonasCommand } from './personas.js';
|
|
9
|
+
export { createAgentsCommand } from './agents.js';
|
|
10
|
+
export { createHealthCommand } from './health.js';
|
|
11
|
+
export { createMcpCommand } from './mcp.js';
|
|
12
|
+
export { createScorecardsCommand } from './scorecards.js';
|
|
13
|
+
export { createKnowledgeCommand } from './knowledge.js';
|
|
14
|
+
export { createMemoryCommand } from './memory.js';
|
|
15
|
+
export { createChatCommand } from './chat.js';
|
|
16
|
+
export { createPromptsCommand } from './prompts.js';
|
|
17
|
+
export { createWorkspacesCommand } from './workspaces.js';
|
|
18
|
+
import 'commander';
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { createAuthCommand, createLoginCommand, createLogoutCommand } from "./auth.js";
|
|
2
|
+
import { createConfigCommand } from "./config.js";
|
|
3
|
+
import { createToolsCommand } from "./tools.js";
|
|
4
|
+
import { createToolsetsCommand } from "./toolsets.js";
|
|
5
|
+
import { createScenariosCommand } from "./scenarios.js";
|
|
6
|
+
import { createCallCommand } from "./call.js";
|
|
7
|
+
import { createCallsCommand } from "./calls.js";
|
|
8
|
+
import { createPersonasCommand } from "./personas.js";
|
|
9
|
+
import { createAgentsCommand } from "./agents.js";
|
|
10
|
+
import { createHealthCommand } from "./health.js";
|
|
11
|
+
import { createMcpCommand } from "./mcp.js";
|
|
12
|
+
import { createScorecardsCommand } from "./scorecards.js";
|
|
13
|
+
import { createKnowledgeCommand } from "./knowledge.js";
|
|
14
|
+
import { createMemoryCommand } from "./memory.js";
|
|
15
|
+
import { createChatCommand } from "./chat.js";
|
|
16
|
+
import { createPromptsCommand } from "./prompts.js";
|
|
17
|
+
import { createWorkspacesCommand } from "./workspaces.js";
|
|
18
|
+
export {
|
|
19
|
+
createAgentsCommand,
|
|
20
|
+
createAuthCommand,
|
|
21
|
+
createCallCommand,
|
|
22
|
+
createCallsCommand,
|
|
23
|
+
createChatCommand,
|
|
24
|
+
createConfigCommand,
|
|
25
|
+
createHealthCommand,
|
|
26
|
+
createKnowledgeCommand,
|
|
27
|
+
createLoginCommand,
|
|
28
|
+
createLogoutCommand,
|
|
29
|
+
createMcpCommand,
|
|
30
|
+
createMemoryCommand,
|
|
31
|
+
createPersonasCommand,
|
|
32
|
+
createPromptsCommand,
|
|
33
|
+
createScenariosCommand,
|
|
34
|
+
createScorecardsCommand,
|
|
35
|
+
createToolsCommand,
|
|
36
|
+
createToolsetsCommand,
|
|
37
|
+
createWorkspacesCommand
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/commands/index.ts"],"sourcesContent":["/**\n * Command exports for the Chanl CLI\n */\n\nexport { createAuthCommand, createLoginCommand, createLogoutCommand } from './auth.js';\nexport { createConfigCommand } from './config.js';\nexport { createToolsCommand } from './tools.js';\nexport { createToolsetsCommand } from './toolsets.js';\nexport { createScenariosCommand } from './scenarios.js';\nexport { createCallCommand } from './call.js';\nexport { createCallsCommand } from './calls.js';\nexport { createPersonasCommand } from './personas.js';\nexport { createAgentsCommand } from './agents.js';\nexport { createHealthCommand } from './health.js';\nexport { createMcpCommand } from './mcp.js';\nexport { createScorecardsCommand } from './scorecards.js';\nexport { createKnowledgeCommand } from './knowledge.js';\nexport { createMemoryCommand } from './memory.js';\nexport { createChatCommand } from './chat.js';\nexport { createPromptsCommand } from './prompts.js';\nexport { createWorkspacesCommand } from './workspaces.js';\n"],"mappings":"AAIA,SAAS,mBAAmB,oBAAoB,2BAA2B;AAC3E,SAAS,2BAA2B;AACpC,SAAS,0BAA0B;AACnC,SAAS,6BAA6B;AACtC,SAAS,8BAA8B;AACvC,SAAS,yBAAyB;AAClC,SAAS,0BAA0B;AACnC,SAAS,6BAA6B;AACtC,SAAS,2BAA2B;AACpC,SAAS,2BAA2B;AACpC,SAAS,wBAAwB;AACjC,SAAS,+BAA+B;AACxC,SAAS,8BAA8B;AACvC,SAAS,2BAA2B;AACpC,SAAS,yBAAyB;AAClC,SAAS,4BAA4B;AACrC,SAAS,+BAA+B;","names":[]}
|
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { readFileSync, existsSync } from "fs";
|
|
5
|
+
import { resolve } from "path";
|
|
6
|
+
import { ChanlSDK } from "@chanl-ai/sdk";
|
|
7
|
+
import { configStore } from "../utils/config-store.js";
|
|
8
|
+
import {
|
|
9
|
+
printError,
|
|
10
|
+
printSuccess,
|
|
11
|
+
printInfo,
|
|
12
|
+
printBlank,
|
|
13
|
+
printSimpleTable,
|
|
14
|
+
printLabel,
|
|
15
|
+
isJsonOutput,
|
|
16
|
+
printJson,
|
|
17
|
+
formatDate
|
|
18
|
+
} from "../utils/output.js";
|
|
19
|
+
function createKnowledgeCommand() {
|
|
20
|
+
const knowledge = new Command("kb").alias("knowledge").description("Manage knowledge base entries (RAG)").addHelpText(
|
|
21
|
+
"after",
|
|
22
|
+
`
|
|
23
|
+
What is Knowledge Base?
|
|
24
|
+
The knowledge base stores documents, FAQs, and other content that AI agents
|
|
25
|
+
can search and retrieve during conversations. Supports text, URLs, and files.
|
|
26
|
+
|
|
27
|
+
Quick Start:
|
|
28
|
+
$ chanl kb list # List all entries
|
|
29
|
+
$ chanl kb add --text "FAQ content" --title "FAQ" # Add text content
|
|
30
|
+
$ chanl kb add --url https://docs.example.com # Add from URL
|
|
31
|
+
$ chanl kb add --file ./docs/guide.pdf # Upload file
|
|
32
|
+
$ chanl kb search "how do I reset password" # Search KB
|
|
33
|
+
|
|
34
|
+
Workflow:
|
|
35
|
+
1. Add content via text, URL, or file upload
|
|
36
|
+
2. Search to verify content is indexed
|
|
37
|
+
3. Associate with agents for RAG retrieval`
|
|
38
|
+
);
|
|
39
|
+
knowledge.command("list").description("List knowledge base entries").option("-s, --search <query>", "Filter by title/content search").option("--source <source>", "Filter by source (text, url, file, manual)").option("--status <status>", "Filter by processing status").option("--folder <folderId>", "Filter by folder ID").option("-l, --limit <number>", "Number of items per page", "20").option("--page <number>", "Page number", "1").addHelpText(
|
|
40
|
+
"after",
|
|
41
|
+
`
|
|
42
|
+
Examples:
|
|
43
|
+
$ chanl kb list # List all entries
|
|
44
|
+
$ chanl kb list --source url # Only URL-sourced entries
|
|
45
|
+
$ chanl kb list --status completed # Only fully processed
|
|
46
|
+
$ chanl kb list --json # Output as JSON`
|
|
47
|
+
).action(handleKnowledgeList);
|
|
48
|
+
knowledge.command("get <id>").description("Get knowledge entry details").option("--chunks", "Include chunk details").addHelpText(
|
|
49
|
+
"after",
|
|
50
|
+
`
|
|
51
|
+
Examples:
|
|
52
|
+
$ chanl kb get abc123 # Get entry details
|
|
53
|
+
$ chanl kb get abc123 --chunks # Include chunks
|
|
54
|
+
$ chanl kb get abc123 --json # Output as JSON`
|
|
55
|
+
).action(handleKnowledgeGet);
|
|
56
|
+
knowledge.command("add").description("Add knowledge content (text, URL, or file)").option("-t, --title <title>", "Title for the entry").option("--text <content>", "Direct text content").option("--url <url>", "URL to fetch content from").option("-f, --file <path>", "File to upload (PDF, TXT, HTML, MD)").option("--folder <folderId>", "Folder ID to organize entry").option("--tags <tags>", "Comma-separated tags").option("--category <category>", "Category for organization").option("--crawl-depth <depth>", "URL crawl depth (0-2)", "0").option("--max-pages <pages>", "Max pages to crawl (1-50)", "10").addHelpText(
|
|
57
|
+
"after",
|
|
58
|
+
`
|
|
59
|
+
Examples:
|
|
60
|
+
$ chanl kb add --text "Content here" --title "FAQ"
|
|
61
|
+
$ chanl kb add --url https://docs.example.com --title "Docs"
|
|
62
|
+
$ chanl kb add --url https://docs.example.com --crawl-depth 1 --max-pages 20
|
|
63
|
+
$ chanl kb add --file ./guide.pdf --title "User Guide"
|
|
64
|
+
$ chanl kb add --text "Content" --tags "faq,support" --category "support"`
|
|
65
|
+
).action(handleKnowledgeAdd);
|
|
66
|
+
knowledge.command("update <id>").description("Update a knowledge entry").option("-t, --title <title>", "New title").option("--content <content>", "New content (text entries only)").option("--tags <tags>", "Comma-separated tags").option("--category <category>", "Category").option("--enabled <boolean>", "Enable/disable for search").addHelpText(
|
|
67
|
+
"after",
|
|
68
|
+
`
|
|
69
|
+
Examples:
|
|
70
|
+
$ chanl kb update abc123 --title "New Title"
|
|
71
|
+
$ chanl kb update abc123 --enabled false
|
|
72
|
+
$ chanl kb update abc123 --tags "updated,important"`
|
|
73
|
+
).action(handleKnowledgeUpdate);
|
|
74
|
+
knowledge.command("delete <id>").description("Delete a knowledge entry").option("-y, --yes", "Skip confirmation prompt").addHelpText(
|
|
75
|
+
"after",
|
|
76
|
+
`
|
|
77
|
+
Examples:
|
|
78
|
+
$ chanl kb delete abc123
|
|
79
|
+
$ chanl kb delete abc123 --yes # Skip confirmation`
|
|
80
|
+
).action(handleKnowledgeDelete);
|
|
81
|
+
knowledge.command("search <query>").description("Search the knowledge base").option("-m, --mode <mode>", "Search mode: hybrid, vector, text", "hybrid").option("-l, --limit <number>", "Max results", "10").option("--min-score <score>", "Minimum similarity score (0-1)").addHelpText(
|
|
82
|
+
"after",
|
|
83
|
+
`
|
|
84
|
+
Search Modes:
|
|
85
|
+
hybrid - Combined vector + text search (default, best results)
|
|
86
|
+
vector - Semantic similarity search
|
|
87
|
+
text - Full-text keyword search
|
|
88
|
+
|
|
89
|
+
Examples:
|
|
90
|
+
$ chanl kb search "how to reset password"
|
|
91
|
+
$ chanl kb search "API authentication" --mode vector
|
|
92
|
+
$ chanl kb search "billing" --limit 5 --min-score 0.7`
|
|
93
|
+
).action(handleKnowledgeSearch);
|
|
94
|
+
knowledge.command("status <taskId>").description("Check processing status of async upload").addHelpText(
|
|
95
|
+
"after",
|
|
96
|
+
`
|
|
97
|
+
Examples:
|
|
98
|
+
$ chanl kb status abc123 # Check task status`
|
|
99
|
+
).action(handleKnowledgeStatus);
|
|
100
|
+
return knowledge;
|
|
101
|
+
}
|
|
102
|
+
async function handleKnowledgeList(options) {
|
|
103
|
+
const apiKey = configStore.getApiKey();
|
|
104
|
+
if (!apiKey) {
|
|
105
|
+
printError("Not logged in", "Run: chanl auth login");
|
|
106
|
+
process.exitCode = 1;
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const sdk = new ChanlSDK({
|
|
110
|
+
baseUrl: configStore.getBaseUrl(),
|
|
111
|
+
apiKey
|
|
112
|
+
});
|
|
113
|
+
const spinner = ora("Fetching knowledge entries...").start();
|
|
114
|
+
try {
|
|
115
|
+
const filters = {
|
|
116
|
+
search: options.search,
|
|
117
|
+
source: options.source,
|
|
118
|
+
processingStatus: options.status,
|
|
119
|
+
folderId: options.folder,
|
|
120
|
+
limit: parseInt(options.limit),
|
|
121
|
+
page: parseInt(options.page)
|
|
122
|
+
};
|
|
123
|
+
const response = await sdk.knowledge.list(filters);
|
|
124
|
+
spinner.stop();
|
|
125
|
+
if (!response.success) {
|
|
126
|
+
printError("Failed to list knowledge entries", response.message);
|
|
127
|
+
process.exitCode = 1;
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const responseData = response.data;
|
|
131
|
+
const entries = responseData?.items || [];
|
|
132
|
+
const total = responseData?.total ?? entries.length;
|
|
133
|
+
if (isJsonOutput()) {
|
|
134
|
+
printJson(response.data);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (entries.length === 0) {
|
|
138
|
+
printInfo("No knowledge entries found");
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
printBlank();
|
|
142
|
+
console.log(chalk.bold(`Knowledge Base (${total} entries)`));
|
|
143
|
+
printBlank();
|
|
144
|
+
printSimpleTable(
|
|
145
|
+
["ID", "Title", "Source", "Status", "Chunks", "Created"],
|
|
146
|
+
entries.map((entry) => [
|
|
147
|
+
entry.id.slice(0, 8),
|
|
148
|
+
(entry.title || "Untitled").slice(0, 40),
|
|
149
|
+
entry.source,
|
|
150
|
+
formatStatus(entry.processingStatus),
|
|
151
|
+
String(entry.chunkCount || "-"),
|
|
152
|
+
formatDate(entry.createdAt)
|
|
153
|
+
])
|
|
154
|
+
);
|
|
155
|
+
printBlank();
|
|
156
|
+
} catch (error) {
|
|
157
|
+
spinner.fail("Failed to list knowledge entries");
|
|
158
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
159
|
+
printError("Error", message);
|
|
160
|
+
process.exitCode = 1;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
async function handleKnowledgeGet(id, options) {
|
|
164
|
+
const apiKey = configStore.getApiKey();
|
|
165
|
+
if (!apiKey) {
|
|
166
|
+
printError("Not logged in", "Run: chanl auth login");
|
|
167
|
+
process.exitCode = 1;
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const sdk = new ChanlSDK({
|
|
171
|
+
baseUrl: configStore.getBaseUrl(),
|
|
172
|
+
apiKey
|
|
173
|
+
});
|
|
174
|
+
const spinner = ora("Fetching knowledge entry...").start();
|
|
175
|
+
try {
|
|
176
|
+
const response = await sdk.knowledge.get(id);
|
|
177
|
+
spinner.stop();
|
|
178
|
+
if (!response.success || !response.data) {
|
|
179
|
+
printError("Knowledge entry not found", response.message);
|
|
180
|
+
process.exitCode = 1;
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const responseData = response.data;
|
|
184
|
+
const entry = "knowledge" in responseData && responseData.knowledge ? responseData.knowledge : responseData;
|
|
185
|
+
if (isJsonOutput()) {
|
|
186
|
+
printJson(entry);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
printBlank();
|
|
190
|
+
console.log(chalk.bold("Knowledge Entry Details"));
|
|
191
|
+
printBlank();
|
|
192
|
+
printLabel("ID", entry.id);
|
|
193
|
+
printLabel("Title", entry.title);
|
|
194
|
+
printLabel("Source", entry.source);
|
|
195
|
+
printLabel("Status", formatStatus(entry.processingStatus));
|
|
196
|
+
if (entry.chunkCount) printLabel("Chunks", entry.chunkCount.toString());
|
|
197
|
+
if (entry.tokenCount) printLabel("Tokens", entry.tokenCount.toString());
|
|
198
|
+
if (entry.folderId) printLabel("Folder", entry.folderId);
|
|
199
|
+
if (entry.metadata?.category) printLabel("Category", entry.metadata.category);
|
|
200
|
+
if (entry.metadata?.tags?.length) {
|
|
201
|
+
printLabel("Tags", entry.metadata.tags.join(", "));
|
|
202
|
+
}
|
|
203
|
+
if (entry.createdAt) printLabel("Created", formatDate(entry.createdAt));
|
|
204
|
+
if (entry.updatedAt) printLabel("Updated", formatDate(entry.updatedAt));
|
|
205
|
+
if (entry.content) {
|
|
206
|
+
printBlank();
|
|
207
|
+
console.log(chalk.bold("Content Preview:"));
|
|
208
|
+
console.log(chalk.dim(entry.content.slice(0, 500) + (entry.content.length > 500 ? "..." : "")));
|
|
209
|
+
}
|
|
210
|
+
if (options.chunks) {
|
|
211
|
+
const chunksResponse = await sdk.knowledge.getChunks(id);
|
|
212
|
+
if (chunksResponse.success && chunksResponse.data) {
|
|
213
|
+
printBlank();
|
|
214
|
+
console.log(chalk.bold(`Chunks (${chunksResponse.data.length}):`));
|
|
215
|
+
chunksResponse.data.slice(0, 5).forEach((chunk, i) => {
|
|
216
|
+
console.log(chalk.dim(` [${i + 1}] ${chunk.content.slice(0, 100)}...`));
|
|
217
|
+
});
|
|
218
|
+
if (chunksResponse.data.length > 5) {
|
|
219
|
+
console.log(chalk.dim(` ... and ${chunksResponse.data.length - 5} more`));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
printBlank();
|
|
224
|
+
} catch (error) {
|
|
225
|
+
spinner.fail("Failed to get knowledge entry");
|
|
226
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
227
|
+
printError("Error", message);
|
|
228
|
+
process.exitCode = 1;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
async function handleKnowledgeAdd(options) {
|
|
232
|
+
const apiKey = configStore.getApiKey();
|
|
233
|
+
if (!apiKey) {
|
|
234
|
+
printError("Not logged in", "Run: chanl auth login");
|
|
235
|
+
process.exitCode = 1;
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
const sources = [options.text, options.url, options.file].filter(Boolean);
|
|
239
|
+
if (sources.length === 0) {
|
|
240
|
+
printError("Missing content", "Provide --text, --url, or --file");
|
|
241
|
+
process.exitCode = 1;
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (sources.length > 1) {
|
|
245
|
+
printError("Too many sources", "Provide only one of --text, --url, or --file");
|
|
246
|
+
process.exitCode = 1;
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const sdk = new ChanlSDK({
|
|
250
|
+
baseUrl: configStore.getBaseUrl(),
|
|
251
|
+
apiKey
|
|
252
|
+
});
|
|
253
|
+
const spinner = ora("Adding knowledge entry...").start();
|
|
254
|
+
try {
|
|
255
|
+
let response;
|
|
256
|
+
if (options.file) {
|
|
257
|
+
const filePath = resolve(options.file);
|
|
258
|
+
if (!existsSync(filePath)) {
|
|
259
|
+
spinner.fail("File not found");
|
|
260
|
+
printError("File not found", filePath);
|
|
261
|
+
process.exitCode = 1;
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const fileBuffer = readFileSync(filePath);
|
|
265
|
+
const filename = options.file.split("/").pop() || "document";
|
|
266
|
+
response = await sdk.knowledge.createFromFile(fileBuffer, filename, {
|
|
267
|
+
title: options.title || filename,
|
|
268
|
+
folderId: options.folder,
|
|
269
|
+
metadata: {
|
|
270
|
+
category: options.category,
|
|
271
|
+
tags: options.tags?.split(",").map((t) => t.trim())
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
} else {
|
|
275
|
+
const createData = {
|
|
276
|
+
title: options.title || (options.url ? "URL Import" : "Text Entry"),
|
|
277
|
+
source: options.url ? "url" : "text",
|
|
278
|
+
content: options.text,
|
|
279
|
+
url: options.url,
|
|
280
|
+
folderId: options.folder,
|
|
281
|
+
metadata: {
|
|
282
|
+
category: options.category,
|
|
283
|
+
tags: options.tags?.split(",").map((t) => t.trim())
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
if (options.url) {
|
|
287
|
+
createData.crawlOptions = {
|
|
288
|
+
depth: parseInt(options.crawlDepth || "0"),
|
|
289
|
+
maxPages: parseInt(options.maxPages || "10"),
|
|
290
|
+
sameDomainOnly: true
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
response = await sdk.knowledge.create(createData);
|
|
294
|
+
}
|
|
295
|
+
spinner.stop();
|
|
296
|
+
if (!response.success || !response.data) {
|
|
297
|
+
printError("Failed to add knowledge entry", response.message);
|
|
298
|
+
process.exitCode = 1;
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const entry = response.data;
|
|
302
|
+
if (isJsonOutput()) {
|
|
303
|
+
printJson(entry);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
printBlank();
|
|
307
|
+
if (entry.taskId) {
|
|
308
|
+
printSuccess(`Knowledge entry queued for processing`);
|
|
309
|
+
printLabel("ID", entry.id);
|
|
310
|
+
printLabel("Task ID", entry.taskId);
|
|
311
|
+
printLabel("Status", formatStatus(entry.processingStatus));
|
|
312
|
+
printInfo(`Track progress: chanl kb status ${entry.taskId}`);
|
|
313
|
+
} else {
|
|
314
|
+
printSuccess(`Knowledge entry created`);
|
|
315
|
+
printLabel("ID", entry.id);
|
|
316
|
+
printLabel("Title", entry.title);
|
|
317
|
+
printLabel("Status", formatStatus(entry.processingStatus));
|
|
318
|
+
}
|
|
319
|
+
printBlank();
|
|
320
|
+
} catch (error) {
|
|
321
|
+
spinner.fail("Failed to add knowledge entry");
|
|
322
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
323
|
+
printError("Error", message);
|
|
324
|
+
process.exitCode = 1;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
async function handleKnowledgeUpdate(id, options) {
|
|
328
|
+
const apiKey = configStore.getApiKey();
|
|
329
|
+
if (!apiKey) {
|
|
330
|
+
printError("Not logged in", "Run: chanl auth login");
|
|
331
|
+
process.exitCode = 1;
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
const sdk = new ChanlSDK({
|
|
335
|
+
baseUrl: configStore.getBaseUrl(),
|
|
336
|
+
apiKey
|
|
337
|
+
});
|
|
338
|
+
const spinner = ora("Updating knowledge entry...").start();
|
|
339
|
+
try {
|
|
340
|
+
const updateData = {};
|
|
341
|
+
if (options.title) updateData.title = options.title;
|
|
342
|
+
if (options.content) updateData.content = options.content;
|
|
343
|
+
if (options.enabled !== void 0) {
|
|
344
|
+
updateData.isEnabled = options.enabled === "true";
|
|
345
|
+
}
|
|
346
|
+
if (options.tags || options.category) {
|
|
347
|
+
updateData.metadata = {
|
|
348
|
+
...options.category && { category: options.category },
|
|
349
|
+
...options.tags && { tags: options.tags.split(",").map((t) => t.trim()) }
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
const response = await sdk.knowledge.update(id, updateData);
|
|
353
|
+
spinner.stop();
|
|
354
|
+
if (!response.success || !response.data) {
|
|
355
|
+
printError("Failed to update knowledge entry", response.message);
|
|
356
|
+
process.exitCode = 1;
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
const responseData = response.data;
|
|
360
|
+
const entry = "knowledge" in responseData && responseData.knowledge ? responseData.knowledge : responseData;
|
|
361
|
+
if (isJsonOutput()) {
|
|
362
|
+
printJson(entry);
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
printBlank();
|
|
366
|
+
printSuccess("Knowledge entry updated");
|
|
367
|
+
printLabel("ID", entry.id);
|
|
368
|
+
printLabel("Title", entry.title);
|
|
369
|
+
printBlank();
|
|
370
|
+
} catch (error) {
|
|
371
|
+
spinner.fail("Failed to update knowledge entry");
|
|
372
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
373
|
+
printError("Error", message);
|
|
374
|
+
process.exitCode = 1;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
async function handleKnowledgeDelete(id, options) {
|
|
378
|
+
const apiKey = configStore.getApiKey();
|
|
379
|
+
if (!apiKey) {
|
|
380
|
+
printError("Not logged in", "Run: chanl auth login");
|
|
381
|
+
process.exitCode = 1;
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
if (!options.yes) {
|
|
385
|
+
const readline = await import("readline");
|
|
386
|
+
const rl = readline.createInterface({
|
|
387
|
+
input: process.stdin,
|
|
388
|
+
output: process.stdout
|
|
389
|
+
});
|
|
390
|
+
const answer = await new Promise((resolve2) => {
|
|
391
|
+
rl.question(chalk.yellow(`Delete knowledge entry ${id}? [y/N] `), resolve2);
|
|
392
|
+
});
|
|
393
|
+
rl.close();
|
|
394
|
+
if (answer.toLowerCase() !== "y") {
|
|
395
|
+
printInfo("Cancelled");
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
const sdk = new ChanlSDK({
|
|
400
|
+
baseUrl: configStore.getBaseUrl(),
|
|
401
|
+
apiKey
|
|
402
|
+
});
|
|
403
|
+
const spinner = ora("Deleting knowledge entry...").start();
|
|
404
|
+
try {
|
|
405
|
+
await sdk.knowledge.delete(id);
|
|
406
|
+
spinner.stop();
|
|
407
|
+
if (isJsonOutput()) {
|
|
408
|
+
printJson({ deleted: true, id });
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
printBlank();
|
|
412
|
+
printSuccess(`Knowledge entry deleted: ${id}`);
|
|
413
|
+
printBlank();
|
|
414
|
+
} catch (error) {
|
|
415
|
+
spinner.fail("Failed to delete knowledge entry");
|
|
416
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
417
|
+
printError("Error", message);
|
|
418
|
+
process.exitCode = 1;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
async function handleKnowledgeSearch(query, options) {
|
|
422
|
+
const apiKey = configStore.getApiKey();
|
|
423
|
+
if (!apiKey) {
|
|
424
|
+
printError("Not logged in", "Run: chanl auth login");
|
|
425
|
+
process.exitCode = 1;
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
const sdk = new ChanlSDK({
|
|
429
|
+
baseUrl: configStore.getBaseUrl(),
|
|
430
|
+
apiKey
|
|
431
|
+
});
|
|
432
|
+
const spinner = ora("Searching knowledge base...").start();
|
|
433
|
+
try {
|
|
434
|
+
const searchData = {
|
|
435
|
+
query,
|
|
436
|
+
mode: options.mode || "hybrid",
|
|
437
|
+
limit: parseInt(options.limit || "10"),
|
|
438
|
+
minScore: options.minScore ? parseFloat(options.minScore) : void 0
|
|
439
|
+
};
|
|
440
|
+
const response = await sdk.knowledge.search(searchData);
|
|
441
|
+
spinner.stop();
|
|
442
|
+
if (!response.success || !response.data) {
|
|
443
|
+
printError("Search failed", response.message);
|
|
444
|
+
process.exitCode = 1;
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
const results = response.data.results || [];
|
|
448
|
+
if (isJsonOutput()) {
|
|
449
|
+
printJson(response.data);
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
printBlank();
|
|
453
|
+
console.log(chalk.bold(`Search Results (${results.length} matches)`));
|
|
454
|
+
console.log(chalk.dim(`Query: "${query}" | Mode: ${options.mode || "hybrid"}`));
|
|
455
|
+
printBlank();
|
|
456
|
+
if (results.length === 0) {
|
|
457
|
+
printInfo("No matching results found");
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
results.forEach((result, index) => {
|
|
461
|
+
console.log(
|
|
462
|
+
chalk.cyan(`[${index + 1}]`) + ` ${chalk.bold(result.title || "Untitled")} ` + chalk.dim(`(score: ${result.score.toFixed(3)})`)
|
|
463
|
+
);
|
|
464
|
+
console.log(chalk.dim(` ${result.content.slice(0, 150)}...`));
|
|
465
|
+
console.log(chalk.dim(` ID: ${result.id || result.knowledgeId}`));
|
|
466
|
+
printBlank();
|
|
467
|
+
});
|
|
468
|
+
} catch (error) {
|
|
469
|
+
spinner.fail("Search failed");
|
|
470
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
471
|
+
printError("Error", message);
|
|
472
|
+
process.exitCode = 1;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
async function handleKnowledgeStatus(taskId) {
|
|
476
|
+
const apiKey = configStore.getApiKey();
|
|
477
|
+
if (!apiKey) {
|
|
478
|
+
printError("Not logged in", "Run: chanl auth login");
|
|
479
|
+
process.exitCode = 1;
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
const sdk = new ChanlSDK({
|
|
483
|
+
baseUrl: configStore.getBaseUrl(),
|
|
484
|
+
apiKey
|
|
485
|
+
});
|
|
486
|
+
const spinner = ora("Checking task status...").start();
|
|
487
|
+
try {
|
|
488
|
+
const response = await sdk.knowledge.getTaskStatus(taskId);
|
|
489
|
+
spinner.stop();
|
|
490
|
+
if (!response.success || !response.data) {
|
|
491
|
+
printError("Task not found", response.message);
|
|
492
|
+
process.exitCode = 1;
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
const task = response.data;
|
|
496
|
+
if (isJsonOutput()) {
|
|
497
|
+
printJson(task);
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
printBlank();
|
|
501
|
+
console.log(chalk.bold("Processing Task Status"));
|
|
502
|
+
printBlank();
|
|
503
|
+
printLabel("Task ID", task.id);
|
|
504
|
+
printLabel("Status", formatStatus(task.status));
|
|
505
|
+
printLabel("Progress", `${task.progress}%`);
|
|
506
|
+
if (task.currentStep) printLabel("Current Step", task.currentStep);
|
|
507
|
+
if (task.documentId) printLabel("Document ID", task.documentId);
|
|
508
|
+
if (task.error) printLabel("Error", chalk.red(task.error));
|
|
509
|
+
if (task.result) {
|
|
510
|
+
printLabel("Chunks", task.result.chunkCount.toString());
|
|
511
|
+
printLabel("Words", task.result.wordCount.toString());
|
|
512
|
+
printLabel("Processing Time", `${task.result.processingTimeMs}ms`);
|
|
513
|
+
}
|
|
514
|
+
printBlank();
|
|
515
|
+
} catch (error) {
|
|
516
|
+
spinner.fail("Failed to get task status");
|
|
517
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
518
|
+
printError("Error", message);
|
|
519
|
+
process.exitCode = 1;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
function formatStatus(status) {
|
|
523
|
+
switch (status) {
|
|
524
|
+
case "completed":
|
|
525
|
+
return chalk.green("completed");
|
|
526
|
+
case "processing":
|
|
527
|
+
return chalk.yellow("processing");
|
|
528
|
+
case "pending":
|
|
529
|
+
return chalk.blue("pending");
|
|
530
|
+
case "failed":
|
|
531
|
+
return chalk.red("failed");
|
|
532
|
+
default:
|
|
533
|
+
return chalk.dim(status || "unknown");
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
export {
|
|
537
|
+
createKnowledgeCommand
|
|
538
|
+
};
|
|
539
|
+
//# sourceMappingURL=knowledge.js.map
|