kontexted 0.1.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.
Files changed (72) hide show
  1. package/README.md +75 -0
  2. package/dist/commands/login.d.ts +2 -0
  3. package/dist/commands/login.js +48 -0
  4. package/dist/commands/logout.d.ts +5 -0
  5. package/dist/commands/logout.js +33 -0
  6. package/dist/commands/mcp.d.ts +15 -0
  7. package/dist/commands/mcp.js +65 -0
  8. package/dist/commands/server/doctor.d.ts +4 -0
  9. package/dist/commands/server/doctor.js +33 -0
  10. package/dist/commands/server/index.d.ts +6 -0
  11. package/dist/commands/server/index.js +100 -0
  12. package/dist/commands/server/init.d.ts +6 -0
  13. package/dist/commands/server/init.js +81 -0
  14. package/dist/commands/server/logs.d.ts +7 -0
  15. package/dist/commands/server/logs.js +39 -0
  16. package/dist/commands/server/start.d.ts +6 -0
  17. package/dist/commands/server/start.js +44 -0
  18. package/dist/commands/server/status.d.ts +4 -0
  19. package/dist/commands/server/status.js +23 -0
  20. package/dist/commands/server/stop.d.ts +6 -0
  21. package/dist/commands/server/stop.js +32 -0
  22. package/dist/commands/show-config.d.ts +5 -0
  23. package/dist/commands/show-config.js +19 -0
  24. package/dist/commands/skill.d.ts +5 -0
  25. package/dist/commands/skill.js +211 -0
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.js +25 -0
  28. package/dist/lib/api-client.d.ts +36 -0
  29. package/dist/lib/api-client.js +130 -0
  30. package/dist/lib/config.d.ts +17 -0
  31. package/dist/lib/config.js +46 -0
  32. package/dist/lib/index.d.ts +6 -0
  33. package/dist/lib/index.js +6 -0
  34. package/dist/lib/logger.d.ts +24 -0
  35. package/dist/lib/logger.js +76 -0
  36. package/dist/lib/mcp-client.d.ts +14 -0
  37. package/dist/lib/mcp-client.js +62 -0
  38. package/dist/lib/oauth.d.ts +42 -0
  39. package/dist/lib/oauth.js +383 -0
  40. package/dist/lib/profile.d.ts +37 -0
  41. package/dist/lib/profile.js +49 -0
  42. package/dist/lib/proxy-server.d.ts +12 -0
  43. package/dist/lib/proxy-server.js +131 -0
  44. package/dist/lib/server/binary.d.ts +27 -0
  45. package/dist/lib/server/binary.js +100 -0
  46. package/dist/lib/server/config.d.ts +45 -0
  47. package/dist/lib/server/config.js +97 -0
  48. package/dist/lib/server/constants.d.ts +29 -0
  49. package/dist/lib/server/constants.js +36 -0
  50. package/dist/lib/server/daemon.d.ts +34 -0
  51. package/dist/lib/server/daemon.js +200 -0
  52. package/dist/lib/server/index.d.ts +4 -0
  53. package/dist/lib/server/index.js +4 -0
  54. package/dist/lib/server-url.d.ts +8 -0
  55. package/dist/lib/server-url.js +25 -0
  56. package/dist/skill-init/index.d.ts +3 -0
  57. package/dist/skill-init/index.js +3 -0
  58. package/dist/skill-init/providers/base.d.ts +26 -0
  59. package/dist/skill-init/providers/base.js +1 -0
  60. package/dist/skill-init/providers/index.d.ts +13 -0
  61. package/dist/skill-init/providers/index.js +17 -0
  62. package/dist/skill-init/providers/opencode.d.ts +5 -0
  63. package/dist/skill-init/providers/opencode.js +48 -0
  64. package/dist/skill-init/templates/index.d.ts +3 -0
  65. package/dist/skill-init/templates/index.js +3 -0
  66. package/dist/skill-init/templates/kontexted-cli.d.ts +2 -0
  67. package/dist/skill-init/templates/kontexted-cli.js +169 -0
  68. package/dist/skill-init/utils.d.ts +66 -0
  69. package/dist/skill-init/utils.js +122 -0
  70. package/dist/types/index.d.ts +67 -0
  71. package/dist/types/index.js +4 -0
  72. package/package.json +48 -0
package/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # Kontexted CLI
2
+
3
+ A command-line tool for Kontexted that provides MCP proxy functionality and workspace management.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g kontexted
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Authentication
14
+
15
+ Log in to a Kontexted server:
16
+
17
+ ```bash
18
+ kontexted login --url https://app.example.com --workspace my-workspace --alias prod
19
+ ```
20
+
21
+ With an alias and write permissions:
22
+
23
+ ```bash
24
+ kontexted login --url https://app.example.com --workspace my-workspace --alias prod --write
25
+ ```
26
+
27
+ ### MCP Proxy Mode
28
+
29
+ Start the MCP proxy server (for use with Claude Desktop or other MCP clients):
30
+
31
+ ```bash
32
+ # Using alias
33
+ kontexted --alias prod
34
+
35
+ # Using workspace name
36
+ kontexted --workspace my-workspace
37
+
38
+ # Enable write mode for this session
39
+ kontexted --alias prod --write
40
+
41
+ # Disable write mode for this session
42
+ kontexted --alias prod --write-off
43
+ ```
44
+
45
+ ### Manage Profiles
46
+
47
+ Show stored profiles:
48
+
49
+ ```bash
50
+ kontexted show-config
51
+ ```
52
+
53
+ Remove a profile:
54
+
55
+ ```bash
56
+ kontexted logout --alias prod
57
+ ```
58
+
59
+ Remove all profiles:
60
+
61
+ ```bash
62
+ kontexted logout
63
+ ```
64
+
65
+ ## Configuration
66
+
67
+ Profiles are stored in `~/.kontexted/profile.json` with OAuth tokens.
68
+
69
+ ## Requirements
70
+
71
+ - Node.js 18 or higher
72
+
73
+ ## License
74
+
75
+ MIT
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerLoginCommand(program: Command): void;
@@ -0,0 +1,48 @@
1
+ import { readConfig, writeConfig } from "../lib/config.js";
2
+ import { addProfile } from "../lib/profile.js";
3
+ import { resolveServerUrl } from "../lib/server-url.js";
4
+ import { createOAuthProvider, waitForOAuthCallback } from "../lib/oauth.js";
5
+ import { logDebug } from "../lib/logger.js";
6
+ export function registerLoginCommand(program) {
7
+ program
8
+ .command("login")
9
+ .description("Authenticate and store a new profile")
10
+ .requiredOption("--url <url>", "Kontexted server URL (e.g. https://app.example.com or app.example.com)")
11
+ .requiredOption("--alias <name>", "Profile alias")
12
+ .requiredOption("--workspace <slug>", "Workspace slug")
13
+ .option("--write", "Enable write operations for this profile by default", false)
14
+ .action(async (options) => {
15
+ const baseUrl = resolveServerUrl(options.url);
16
+ logDebug(`[LOGIN] Starting login flow - URL: ${baseUrl}, Alias: ${options.alias}, Workspace: ${options.workspace}`);
17
+ const config = await readConfig();
18
+ const oauth = {};
19
+ const persist = async () => {
20
+ await writeConfig(config);
21
+ };
22
+ // Create OAuth provider
23
+ const provider = createOAuthProvider(oauth, persist, baseUrl);
24
+ // 1. Register OAuth client
25
+ logDebug(`[LOGIN] Registering OAuth client...`);
26
+ await provider.registerClient();
27
+ // 2. Get authorization URL and open browser
28
+ const authUrl = await provider.getAuthorizationUrl();
29
+ logDebug(`[LOGIN] Opening browser for authorization...`);
30
+ provider.redirectToAuthorization(authUrl);
31
+ // 3. Wait for callback with auth code
32
+ logDebug(`[LOGIN] Waiting for authorization callback...`);
33
+ const authCode = await waitForOAuthCallback();
34
+ // 4. Exchange code for tokens
35
+ logDebug(`[LOGIN] Exchanging authorization code for tokens...`);
36
+ await provider.exchangeCodeForToken(authCode);
37
+ // Store the profile
38
+ const profile = {
39
+ serverUrl: baseUrl,
40
+ workspace: options.workspace,
41
+ write: options.write ?? false,
42
+ oauth,
43
+ };
44
+ addProfile(config, options.alias, profile);
45
+ await writeConfig(config);
46
+ console.log(`✓ Login successful. Profile stored as: ${options.alias}`);
47
+ });
48
+ }
@@ -0,0 +1,5 @@
1
+ import type { Command } from "commander";
2
+ /**
3
+ * Register the logout command
4
+ */
5
+ export declare function registerLogoutCommand(program: Command): void;
@@ -0,0 +1,33 @@
1
+ import { readConfig, writeConfig, removeConfig } from "../lib/config.js";
2
+ import { profileExists, removeProfile } from "../lib/profile.js";
3
+ /**
4
+ * Register the logout command
5
+ */
6
+ export function registerLogoutCommand(program) {
7
+ program
8
+ .command("logout")
9
+ .description("Remove stored profiles")
10
+ .option("--alias <name>", "Remove specific profile by alias")
11
+ .action(async (options) => {
12
+ const config = await readConfig();
13
+ // No alias specified: remove all profiles
14
+ if (!options.alias) {
15
+ await removeConfig();
16
+ console.log("✓ Removed all profiles.");
17
+ return;
18
+ }
19
+ const profileKey = options.alias;
20
+ if (!profileExists(config, profileKey)) {
21
+ throw new Error(`Profile not found: ${profileKey}`);
22
+ }
23
+ removeProfile(config, profileKey);
24
+ if (Object.keys(config.profiles).length === 0) {
25
+ await removeConfig();
26
+ console.log("✓ Removed last profile. Config file removed.");
27
+ }
28
+ else {
29
+ await writeConfig(config);
30
+ console.log(`✓ Removed profile: ${profileKey}`);
31
+ }
32
+ });
33
+ }
@@ -0,0 +1,15 @@
1
+ import type { Command } from "commander";
2
+ interface McpOptions {
3
+ alias?: string;
4
+ write?: boolean;
5
+ writeOff?: boolean;
6
+ }
7
+ /**
8
+ * Start the MCP proxy server
9
+ */
10
+ declare function startMcpProxy(options: McpOptions): Promise<void>;
11
+ /**
12
+ * Register the MCP proxy command
13
+ */
14
+ export declare function registerMcpCommand(program: Command): void;
15
+ export { startMcpProxy };
@@ -0,0 +1,65 @@
1
+ import { readConfig, writeConfig } from "../lib/config.js";
2
+ import { getProfile } from "../lib/profile.js";
3
+ import { connectRemoteClient, UnauthorizedError } from "../lib/mcp-client.js";
4
+ import { startProxyServer } from "../lib/proxy-server.js";
5
+ /**
6
+ * Start the MCP proxy server
7
+ */
8
+ async function startMcpProxy(options) {
9
+ const config = await readConfig();
10
+ const profileKey = options.alias;
11
+ if (!profileKey) {
12
+ throw new Error("Missing --alias. Required for MCP proxy mode.\n" +
13
+ "Run 'kontexted mcp --help' for usage information.");
14
+ }
15
+ if (options.write && options.writeOff) {
16
+ throw new Error("Cannot specify both --write and --write-off");
17
+ }
18
+ const profile = getProfile(config, profileKey);
19
+ if (!profile) {
20
+ throw new Error(`Profile not found: ${profileKey}. Run 'kontexted login' first.`);
21
+ }
22
+ // Determine write mode
23
+ let writeEnabled = profile.write ?? false;
24
+ if (options.write) {
25
+ writeEnabled = true;
26
+ }
27
+ else if (options.writeOff) {
28
+ writeEnabled = false;
29
+ }
30
+ const persist = async () => {
31
+ await writeConfig(config);
32
+ };
33
+ try {
34
+ const { client } = await connectRemoteClient(profile.serverUrl, profile.oauth, persist, { allowInteractive: false });
35
+ const toolList = await client.listTools();
36
+ await startProxyServer({
37
+ client,
38
+ workspaceSlug: profile.workspace,
39
+ tools: toolList.tools,
40
+ writeEnabled,
41
+ });
42
+ }
43
+ catch (error) {
44
+ if (error instanceof UnauthorizedError) {
45
+ console.error("Error: Unauthorized. Run 'kontexted login' first.");
46
+ process.exit(1);
47
+ }
48
+ throw error;
49
+ }
50
+ }
51
+ /**
52
+ * Register the MCP proxy command
53
+ */
54
+ export function registerMcpCommand(program) {
55
+ program
56
+ .command("mcp")
57
+ .description("Start MCP proxy server")
58
+ .requiredOption("--alias <name>", "Profile alias to use")
59
+ .option("--write", "Override to enable write operations")
60
+ .option("--write-off", "Override to disable write operations")
61
+ .action(async (options) => {
62
+ await startMcpProxy(options);
63
+ });
64
+ }
65
+ export { startMcpProxy };
@@ -0,0 +1,4 @@
1
+ export declare const command = "doctor";
2
+ export declare const desc = "Run diagnostic checks";
3
+ export declare const builder: (yargs: any) => any;
4
+ export declare const handler: () => Promise<void>;
@@ -0,0 +1,33 @@
1
+ import { existsSync } from 'fs';
2
+ import { isPlatformSupported, getPlatform, getBinaryPath, configExists, loadConfig, getServerStatus, } from '../../lib/server/index.js';
3
+ import { CONFIG_FILE, DATA_DIR } from '../../lib/server/constants.js';
4
+ const DOCKER_URL = 'https://hub.docker.com/r/kontexted/kontexted';
5
+ // ============ Yargs Command Module ============
6
+ export const command = 'doctor';
7
+ export const desc = 'Run diagnostic checks';
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ export const builder = (yargs) => yargs;
10
+ export const handler = async () => {
11
+ console.log('--- Server Diagnostics ---\n');
12
+ const platform = getPlatform();
13
+ const platformOk = isPlatformSupported();
14
+ console.log(`${platformOk ? '✓' : '✗'} Platform: ${platform} ${platformOk ? '(supported)' : '(not supported)'}`);
15
+ if (!platformOk)
16
+ console.log(` → Consider using Docker: ${DOCKER_URL}`);
17
+ const binaryPath = getBinaryPath();
18
+ console.log(`${binaryPath ? '✓' : '✗'} Binary: ${binaryPath || 'not found'}`);
19
+ if (!binaryPath)
20
+ console.log(' → Reinstall @kontexted/cli');
21
+ const configOk = configExists();
22
+ console.log(`${configOk ? '✓' : '✗'} Config: ${configOk ? CONFIG_FILE : 'not found'}`);
23
+ if (!configOk)
24
+ console.log(' → Run: kontexted server init');
25
+ if (configOk) {
26
+ const config = loadConfig();
27
+ const dbPath = config?.database?.url || `${DATA_DIR}/kontexted.db`;
28
+ const dbOk = existsSync(dbPath);
29
+ console.log(`${dbOk ? '✓' : '⚠'} Database: ${dbPath}`);
30
+ }
31
+ const serverStatus = getServerStatus();
32
+ console.log(`Server: ${serverStatus.running ? `Running (PID: ${serverStatus.pid})` : 'Not running'}`);
33
+ };
@@ -0,0 +1,6 @@
1
+ import type { Command } from 'commander';
2
+ export declare const command = "server";
3
+ export declare const desc = "Manage Kontexted server";
4
+ export declare const builder: (yargs: any) => any;
5
+ export declare const handler: () => void;
6
+ export declare function registerServerCommand(program: Command): void;
@@ -0,0 +1,100 @@
1
+ import yargs from 'yargs';
2
+ import * as initCmd from './init.js';
3
+ import * as startCmd from './start.js';
4
+ import * as stopCmd from './stop.js';
5
+ import * as statusCmd from './status.js';
6
+ import * as logsCmd from './logs.js';
7
+ import * as doctorCmd from './doctor.js';
8
+ // Yargs-style exports (as requested by user)
9
+ export const command = 'server';
10
+ export const desc = 'Manage Kontexted server';
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
+ export const builder = (yargs) => {
13
+ return yargs
14
+ .command(initCmd)
15
+ .command(startCmd)
16
+ .command(stopCmd)
17
+ .command(statusCmd)
18
+ .command(logsCmd)
19
+ .command(doctorCmd)
20
+ .demandCommand()
21
+ .help();
22
+ };
23
+ export const handler = () => { };
24
+ // ============ Register with Commander ============
25
+ export function registerServerCommand(program) {
26
+ const serverCmd = program.command('server').description('Manage Kontexted server');
27
+ // init
28
+ serverCmd
29
+ .command('init')
30
+ .description(initCmd.desc)
31
+ .option('-i, --interactive', 'Interactive mode to customize configuration')
32
+ .action(async (opts) => {
33
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
34
+ await yargs(['init'])
35
+ .command(initCmd)
36
+ .option('interactive', { type: 'boolean', default: false })
37
+ .parse();
38
+ });
39
+ // start
40
+ serverCmd
41
+ .command('start')
42
+ .description(startCmd.desc)
43
+ .option('-f, --foreground', 'Run server in foreground (blocking)')
44
+ .action(async (opts) => {
45
+ const args = opts.foreground ? ['start', '--foreground'] : ['start'];
46
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
47
+ await yargs(args)
48
+ .command(startCmd)
49
+ .parse();
50
+ });
51
+ // stop
52
+ serverCmd
53
+ .command('stop')
54
+ .description(stopCmd.desc)
55
+ .option('--force', 'Force kill the server (SIGKILL)')
56
+ .action(async (opts) => {
57
+ const args = opts.force ? ['stop', '--force'] : ['stop'];
58
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
59
+ await yargs(args)
60
+ .command(stopCmd)
61
+ .parse();
62
+ });
63
+ // status
64
+ serverCmd
65
+ .command('status')
66
+ .description(statusCmd.desc)
67
+ .action(async () => {
68
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
+ await yargs(['status'])
70
+ .command(statusCmd)
71
+ .parse();
72
+ });
73
+ // logs
74
+ serverCmd
75
+ .command('logs')
76
+ .description(logsCmd.desc)
77
+ .option('-f, --follow', 'Follow log output in real-time')
78
+ .option('-n, --lines <number>', 'Number of lines to show', '50')
79
+ .action(async (opts) => {
80
+ const args = ['logs'];
81
+ if (opts.follow)
82
+ args.push('--follow');
83
+ if (opts.lines)
84
+ args.push('--lines', opts.lines.toString());
85
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
86
+ await yargs(args)
87
+ .command(logsCmd)
88
+ .parse();
89
+ });
90
+ // doctor
91
+ serverCmd
92
+ .command('doctor')
93
+ .description(doctorCmd.desc)
94
+ .action(async () => {
95
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
96
+ await yargs(['doctor'])
97
+ .command(doctorCmd)
98
+ .parse();
99
+ });
100
+ }
@@ -0,0 +1,6 @@
1
+ export declare const command = "init";
2
+ export declare const desc = "Initialize server configuration";
3
+ export declare const builder: (yargs: any) => any;
4
+ export declare const handler: (argv: {
5
+ interactive?: boolean;
6
+ }) => Promise<void>;
@@ -0,0 +1,81 @@
1
+ import { configExists, getDefaultConfig, saveConfig, } from '../../lib/server/index.js';
2
+ import { CONFIG_FILE, DATA_DIR } from '../../lib/server/constants.js';
3
+ import * as readline from 'readline';
4
+ // ============ Helper Functions ============
5
+ function createPrompt() {
6
+ return readline.createInterface({
7
+ input: process.stdin,
8
+ output: process.stdout,
9
+ });
10
+ }
11
+ function promptQuestion(rl, question) {
12
+ return new Promise((resolve) => {
13
+ rl.question(question, (answer) => resolve(answer));
14
+ });
15
+ }
16
+ async function runInit(interactive) {
17
+ if (interactive) {
18
+ const rl = createPrompt();
19
+ try {
20
+ if (configExists()) {
21
+ const answer = await promptQuestion(rl, 'Config already exists. Overwrite? (y/N): ');
22
+ if (answer.trim().toLowerCase() !== 'y') {
23
+ console.log('Initialization cancelled.');
24
+ return;
25
+ }
26
+ }
27
+ console.log('\n--- Server Configuration ---');
28
+ const dialectAnswer = await promptQuestion(rl, 'Database dialect (sqlite/postgresql) [sqlite]: ');
29
+ const dialect = (dialectAnswer.trim().toLowerCase() || 'sqlite');
30
+ if (dialect !== 'sqlite' && dialect !== 'postgresql') {
31
+ console.log('Invalid dialect. Using sqlite.');
32
+ }
33
+ const defaultUrl = dialect === 'sqlite' ? `${DATA_DIR}/kontexted.db` : 'postgresql://localhost:5432/kontexted';
34
+ const urlAnswer = await promptQuestion(rl, `Database URL [${defaultUrl}]: `);
35
+ const databaseUrl = urlAnswer.trim() || defaultUrl;
36
+ const portAnswer = await promptQuestion(rl, 'Server port [3000]: ');
37
+ const port = parseInt(portAnswer.trim(), 10) || 3000;
38
+ const hostAnswer = await promptQuestion(rl, 'Server host [127.0.0.1]: ');
39
+ const host = hostAnswer.trim() || '127.0.0.1';
40
+ const levelAnswer = await promptQuestion(rl, 'Log level (debug/info/warn/error) [info]: ');
41
+ const level = (levelAnswer.trim().toLowerCase() || 'info');
42
+ const config = {
43
+ database: { dialect, url: databaseUrl },
44
+ server: { port, host },
45
+ logging: { level },
46
+ collab: { tokenSecret: getDefaultConfig().collab.tokenSecret },
47
+ };
48
+ saveConfig(config);
49
+ console.log('\n✓ Configuration saved to:', CONFIG_FILE);
50
+ }
51
+ finally {
52
+ rl.close();
53
+ }
54
+ }
55
+ else {
56
+ if (configExists()) {
57
+ console.error('Error: Configuration already exists.');
58
+ console.log(' Run with --interactive to reinitialize.');
59
+ process.exit(1);
60
+ }
61
+ const config = getDefaultConfig();
62
+ saveConfig(config);
63
+ console.log('✓ Configuration created:', CONFIG_FILE);
64
+ console.log(' Database:', config.database.url);
65
+ console.log(' Server:', `${config.server.host}:${config.server.port}`);
66
+ }
67
+ }
68
+ // ============ Yargs Command Module ============
69
+ export const command = 'init';
70
+ export const desc = 'Initialize server configuration';
71
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
72
+ export const builder = (yargs) => {
73
+ return yargs.option('interactive', {
74
+ alias: 'i',
75
+ type: 'boolean',
76
+ description: 'Interactive mode to customize configuration',
77
+ });
78
+ };
79
+ export const handler = async (argv) => {
80
+ await runInit(argv.interactive ?? false);
81
+ };
@@ -0,0 +1,7 @@
1
+ export declare const command = "logs";
2
+ export declare const desc = "View server logs";
3
+ export declare const builder: (yargs: any) => any;
4
+ export declare const handler: (argv: {
5
+ follow?: boolean;
6
+ lines?: number;
7
+ }) => Promise<void>;
@@ -0,0 +1,39 @@
1
+ import { spawn } from 'child_process';
2
+ import { existsSync } from 'fs';
3
+ import { LOG_FILE } from '../../lib/server/constants.js';
4
+ // ============ Yargs Command Module ============
5
+ export const command = 'logs';
6
+ export const desc = 'View server logs';
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
+ export const builder = (yargs) => {
9
+ return yargs
10
+ .option('follow', {
11
+ alias: 'f',
12
+ type: 'boolean',
13
+ description: 'Follow log output in real-time',
14
+ })
15
+ .option('lines', {
16
+ alias: 'n',
17
+ type: 'number',
18
+ description: 'Number of lines to show',
19
+ default: 50,
20
+ });
21
+ };
22
+ export const handler = async (argv) => {
23
+ if (!existsSync(LOG_FILE)) {
24
+ console.log('No logs available');
25
+ return;
26
+ }
27
+ if (argv.follow) {
28
+ console.log(`Following ${LOG_FILE}... (Ctrl+C to exit)`);
29
+ const tail = spawn('tail', ['-f', LOG_FILE]);
30
+ tail.stdout.on('data', (data) => process.stdout.write(data));
31
+ tail.stderr.on('data', (data) => process.stderr.write(data));
32
+ process.on('SIGINT', () => { tail.kill(); process.exit(0); });
33
+ }
34
+ else {
35
+ const lines = argv.lines ?? 50;
36
+ const tail = spawn('tail', ['-n', lines.toString(), LOG_FILE]);
37
+ tail.stdout.on('data', (data) => process.stdout.write(data));
38
+ }
39
+ };
@@ -0,0 +1,6 @@
1
+ export declare const command = "start";
2
+ export declare const desc = "Start the Kontexted server";
3
+ export declare const builder: (yargs: any) => any;
4
+ export declare const handler: (argv: {
5
+ foreground?: boolean;
6
+ }) => Promise<void>;
@@ -0,0 +1,44 @@
1
+ import { isPlatformSupported, getPlatform, getBinaryPath, configExists, getServerStatus, startServer, } from '../../lib/server/index.js';
2
+ const DOCKER_URL = 'https://hub.docker.com/r/kontexted/kontexted';
3
+ function checkPrerequisites() {
4
+ if (!isPlatformSupported()) {
5
+ return { valid: false, error: `Platform not supported: ${getPlatform()}. Consider using Docker: ${DOCKER_URL}` };
6
+ }
7
+ if (!getBinaryPath()) {
8
+ return { valid: false, error: 'Server binary not found. Run `kontexted server install` first.' };
9
+ }
10
+ if (!configExists()) {
11
+ return { valid: false, error: 'Configuration not found. Run `kontexted server init` first.' };
12
+ }
13
+ const status = getServerStatus();
14
+ if (status.running && status.pid) {
15
+ return { valid: false, error: `Server is already running (PID: ${status.pid})` };
16
+ }
17
+ return { valid: true };
18
+ }
19
+ // ============ Yargs Command Module ============
20
+ export const command = 'start';
21
+ export const desc = 'Start the Kontexted server';
22
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
+ export const builder = (yargs) => {
24
+ return yargs.option('foreground', {
25
+ alias: 'f',
26
+ type: 'boolean',
27
+ description: 'Run server in foreground (blocking)',
28
+ });
29
+ };
30
+ export const handler = async (argv) => {
31
+ const check = checkPrerequisites();
32
+ if (!check.valid) {
33
+ console.error('Error:', check.error);
34
+ process.exit(1);
35
+ }
36
+ try {
37
+ const pid = await startServer({ foreground: argv.foreground });
38
+ console.log(argv.foreground ? `Server running (PID: ${pid})` : `Server started (PID: ${pid})`);
39
+ }
40
+ catch (error) {
41
+ console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
42
+ process.exit(1);
43
+ }
44
+ };
@@ -0,0 +1,4 @@
1
+ export declare const command = "status";
2
+ export declare const desc = "Show server status";
3
+ export declare const builder: (yargs: any) => any;
4
+ export declare const handler: () => Promise<void>;
@@ -0,0 +1,23 @@
1
+ import { getServerStatus, loadConfig } from '../../lib/server/index.js';
2
+ import { CONFIG_FILE, LOG_FILE } from '../../lib/server/constants.js';
3
+ // ============ Yargs Command Module ============
4
+ export const command = 'status';
5
+ export const desc = 'Show server status';
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
+ export const builder = (yargs) => yargs;
8
+ export const handler = async () => {
9
+ const status = getServerStatus();
10
+ if (!status.running) {
11
+ console.log('Server Status: Not running');
12
+ return;
13
+ }
14
+ const config = loadConfig();
15
+ console.log('Server Status: Running');
16
+ console.log(` PID: ${status.pid}`);
17
+ if (config) {
18
+ console.log(` Port: ${config.server.port}`);
19
+ console.log(` Host: ${config.server.host}`);
20
+ }
21
+ console.log(` Config: ${CONFIG_FILE}`);
22
+ console.log(` Logs: ${LOG_FILE}`);
23
+ };
@@ -0,0 +1,6 @@
1
+ export declare const command = "stop";
2
+ export declare const desc = "Stop the Kontexted server";
3
+ export declare const builder: (yargs: any) => any;
4
+ export declare const handler: (argv: {
5
+ force?: boolean;
6
+ }) => Promise<void>;
@@ -0,0 +1,32 @@
1
+ import { getServerStatus, stopServer } from '../../lib/server/index.js';
2
+ // ============ Yargs Command Module ============
3
+ export const command = 'stop';
4
+ export const desc = 'Stop the Kontexted server';
5
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
+ export const builder = (yargs) => {
7
+ return yargs.option('force', {
8
+ type: 'boolean',
9
+ description: 'Force kill the server (SIGKILL)',
10
+ });
11
+ };
12
+ export const handler = async (argv) => {
13
+ const status = getServerStatus();
14
+ if (!status.running) {
15
+ console.log('Server is not running');
16
+ return;
17
+ }
18
+ try {
19
+ const stopped = await stopServer({ force: argv.force ?? false });
20
+ if (stopped) {
21
+ console.log('Server stopped');
22
+ }
23
+ else {
24
+ console.error('Error: Failed to stop server');
25
+ process.exit(1);
26
+ }
27
+ }
28
+ catch (error) {
29
+ console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
30
+ process.exit(1);
31
+ }
32
+ };
@@ -0,0 +1,5 @@
1
+ import type { Command } from "commander";
2
+ /**
3
+ * Register the show-config command
4
+ */
5
+ export declare function registerShowConfigCommand(program: Command): void;