kontexted 0.1.6 → 0.1.8
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.
|
@@ -33,10 +33,10 @@ async function runInit(interactive) {
|
|
|
33
33
|
const defaultUrl = dialect === 'sqlite' ? `${DATA_DIR}/kontexted.db` : 'postgresql://localhost:5432/kontexted';
|
|
34
34
|
const urlAnswer = await promptQuestion(rl, `Database URL [${defaultUrl}]: `);
|
|
35
35
|
const databaseUrl = urlAnswer.trim() || defaultUrl;
|
|
36
|
-
const portAnswer = await promptQuestion(rl, 'Server port [
|
|
37
|
-
const port = parseInt(portAnswer.trim(), 10) ||
|
|
38
|
-
const hostAnswer = await promptQuestion(rl, 'Server host [
|
|
39
|
-
const host = hostAnswer.trim() || '
|
|
36
|
+
const portAnswer = await promptQuestion(rl, 'Server port [4729]: ');
|
|
37
|
+
const port = parseInt(portAnswer.trim(), 10) || 4729;
|
|
38
|
+
const hostAnswer = await promptQuestion(rl, 'Server host [localhost]: ');
|
|
39
|
+
const host = hostAnswer.trim() || 'localhost';
|
|
40
40
|
const levelAnswer = await promptQuestion(rl, 'Log level (debug/info/warn/error) [info]: ');
|
|
41
41
|
const level = (levelAnswer.trim().toLowerCase() || 'info');
|
|
42
42
|
const migrationsDir = getMigrationsDir();
|
|
@@ -44,12 +44,17 @@ async function runInit(interactive) {
|
|
|
44
44
|
const defaultConfig = getDefaultConfig();
|
|
45
45
|
const config = {
|
|
46
46
|
database: { dialect, url: databaseUrl },
|
|
47
|
-
server: {
|
|
47
|
+
server: {
|
|
48
|
+
port,
|
|
49
|
+
host,
|
|
50
|
+
trustedOrigins: defaultConfig.server.trustedOrigins,
|
|
51
|
+
},
|
|
48
52
|
logging: { level },
|
|
49
53
|
collab: { tokenSecret: defaultConfig.collab.tokenSecret },
|
|
50
54
|
auth: {
|
|
51
55
|
betterAuthSecret: defaultConfig.auth.betterAuthSecret,
|
|
52
56
|
inviteCode: defaultConfig.auth.inviteCode,
|
|
57
|
+
method: defaultConfig.auth.method,
|
|
53
58
|
},
|
|
54
59
|
paths: {
|
|
55
60
|
migrationsDir: migrationsDir || undefined,
|
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
import { isPlatformSupported, getPlatform, getBinaryPath, configExists, getServerStatus, startServer, } from '../../lib/server/index.js';
|
|
1
|
+
import { isPlatformSupported, getPlatform, getBinaryPath, configExists, getServerStatus, startServer, loadConfig, } from '../../lib/server/index.js';
|
|
2
2
|
const DOCKER_URL = 'https://hub.docker.com/r/rabbyte-tech/kontexted';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a clickable terminal hyperlink using OSC 8 escape sequence
|
|
5
|
+
* Falls back to plain URL for terminals that don't support it
|
|
6
|
+
*/
|
|
7
|
+
function formatClickableUrl(url, text) {
|
|
8
|
+
const linkText = text || url;
|
|
9
|
+
// OSC 8 escape sequence: \x1b]8;;url\x1b\\text\x1b]8;;\x1b\\
|
|
10
|
+
return `\x1b]8;;${url}\x1b\\${linkText}\x1b]8;;\x1b\\`;
|
|
11
|
+
}
|
|
3
12
|
function checkPrerequisites() {
|
|
4
13
|
if (!isPlatformSupported()) {
|
|
5
14
|
return { valid: false, error: `Platform not supported: ${getPlatform()}. Consider using Docker: ${DOCKER_URL}` };
|
|
@@ -35,7 +44,13 @@ export const handler = async (argv) => {
|
|
|
35
44
|
}
|
|
36
45
|
try {
|
|
37
46
|
const pid = await startServer({ foreground: argv.foreground });
|
|
38
|
-
|
|
47
|
+
// Load config to get host and port
|
|
48
|
+
const config = loadConfig();
|
|
49
|
+
const host = config?.server.host || 'localhost';
|
|
50
|
+
const port = config?.server.port || 4729;
|
|
51
|
+
const url = `http://${host}:${port}`;
|
|
52
|
+
console.log(`Server started (PID: ${pid})`);
|
|
53
|
+
console.log(` → ${formatClickableUrl(url)}`);
|
|
39
54
|
}
|
|
40
55
|
catch (error) {
|
|
41
56
|
console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
|
|
@@ -9,6 +9,7 @@ export interface ServerConfig {
|
|
|
9
9
|
server: {
|
|
10
10
|
port: number;
|
|
11
11
|
host: string;
|
|
12
|
+
trustedOrigins?: string[];
|
|
12
13
|
};
|
|
13
14
|
logging: {
|
|
14
15
|
level: 'debug' | 'info' | 'warn' | 'error';
|
|
@@ -18,7 +19,14 @@ export interface ServerConfig {
|
|
|
18
19
|
};
|
|
19
20
|
auth: {
|
|
20
21
|
betterAuthSecret: string;
|
|
22
|
+
betterAuthUrl?: string;
|
|
21
23
|
inviteCode: string;
|
|
24
|
+
method?: 'email-password' | 'keycloak';
|
|
25
|
+
keycloak?: {
|
|
26
|
+
clientId: string;
|
|
27
|
+
clientSecret: string;
|
|
28
|
+
issuer: string;
|
|
29
|
+
};
|
|
22
30
|
};
|
|
23
31
|
paths?: {
|
|
24
32
|
publicDir?: string;
|
|
@@ -39,8 +39,9 @@ export function getDefaultConfig() {
|
|
|
39
39
|
url: `${DATA_DIR}/kontexted.db`,
|
|
40
40
|
},
|
|
41
41
|
server: {
|
|
42
|
-
port:
|
|
43
|
-
host: '
|
|
42
|
+
port: 4729,
|
|
43
|
+
host: 'localhost',
|
|
44
|
+
trustedOrigins: [],
|
|
44
45
|
},
|
|
45
46
|
logging: {
|
|
46
47
|
level: 'info',
|
|
@@ -51,6 +52,7 @@ export function getDefaultConfig() {
|
|
|
51
52
|
auth: {
|
|
52
53
|
betterAuthSecret: generateBetterAuthSecret(),
|
|
53
54
|
inviteCode: generateInviteCode(),
|
|
55
|
+
method: 'email-password',
|
|
54
56
|
},
|
|
55
57
|
};
|
|
56
58
|
// Add paths if platform package is available
|
|
@@ -87,14 +89,17 @@ export function loadConfig() {
|
|
|
87
89
|
const tokenSecret = parsed.collab?.tokenSecret;
|
|
88
90
|
const betterAuthSecret = parsed.auth?.betterAuthSecret;
|
|
89
91
|
const inviteCode = parsed.auth?.inviteCode;
|
|
90
|
-
|
|
92
|
+
const config = {
|
|
91
93
|
database: {
|
|
92
94
|
dialect: parsed.database.dialect || 'sqlite',
|
|
93
95
|
url: parsed.database.url,
|
|
94
96
|
},
|
|
95
97
|
server: {
|
|
96
|
-
port: parsed.server.port ||
|
|
97
|
-
host: parsed.server.host || '
|
|
98
|
+
port: parsed.server.port || 4729,
|
|
99
|
+
host: parsed.server.host || 'localhost',
|
|
100
|
+
...(Array.isArray(parsed.server.trustedOrigins) && parsed.server.trustedOrigins.length > 0
|
|
101
|
+
? { trustedOrigins: parsed.server.trustedOrigins }
|
|
102
|
+
: {}),
|
|
98
103
|
},
|
|
99
104
|
logging: {
|
|
100
105
|
level: parsed.logging?.level || 'info',
|
|
@@ -105,12 +110,22 @@ export function loadConfig() {
|
|
|
105
110
|
auth: {
|
|
106
111
|
betterAuthSecret: betterAuthSecret || generateBetterAuthSecret(),
|
|
107
112
|
inviteCode: inviteCode || generateInviteCode(),
|
|
113
|
+
...(parsed.auth?.betterAuthUrl ? { betterAuthUrl: parsed.auth.betterAuthUrl } : {}),
|
|
114
|
+
...(parsed.auth?.method ? { method: parsed.auth.method } : {}),
|
|
115
|
+
...(parsed.auth?.keycloak ? {
|
|
116
|
+
keycloak: {
|
|
117
|
+
clientId: parsed.auth.keycloak.clientId,
|
|
118
|
+
clientSecret: parsed.auth.keycloak.clientSecret,
|
|
119
|
+
issuer: parsed.auth.keycloak.issuer,
|
|
120
|
+
},
|
|
121
|
+
} : {}),
|
|
108
122
|
},
|
|
109
123
|
paths: {
|
|
110
124
|
publicDir: parsed.paths?.publicDir,
|
|
111
125
|
migrationsDir: parsed.paths?.migrationsDir,
|
|
112
126
|
},
|
|
113
127
|
};
|
|
128
|
+
return config;
|
|
114
129
|
}
|
|
115
130
|
catch (error) {
|
|
116
131
|
console.warn('Failed to load config file:', error instanceof Error ? error.message : 'Unknown error');
|
|
@@ -2,6 +2,7 @@ import { spawn } from 'child_process';
|
|
|
2
2
|
import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
|
|
3
3
|
import { mkdirSync, closeSync, openSync } from 'fs';
|
|
4
4
|
import { getBinaryPath } from './binary.js';
|
|
5
|
+
import { loadConfig } from './config.js';
|
|
5
6
|
import { LOG_FILE, PID_FILE, LOGS_DIR, KONTEXTED_DIR } from './constants.js';
|
|
6
7
|
/**
|
|
7
8
|
* Ensures required directories exist
|
|
@@ -62,6 +63,33 @@ export async function startServer(options = {}) {
|
|
|
62
63
|
throw new Error('Server binary not found. Please ensure the platform package is installed.');
|
|
63
64
|
}
|
|
64
65
|
ensureDirectories();
|
|
66
|
+
// Load config to get server host/port for Better Auth environment variables
|
|
67
|
+
const config = loadConfig();
|
|
68
|
+
const host = config?.server.host || 'localhost';
|
|
69
|
+
const port = config?.server.port || 4729;
|
|
70
|
+
const serverUrl = `http://${host}:${port}`;
|
|
71
|
+
// Build the trusted origins list from config or fall back to server URL
|
|
72
|
+
const trustedOrigins = config?.server.trustedOrigins?.length
|
|
73
|
+
? config.server.trustedOrigins.join(',')
|
|
74
|
+
: serverUrl;
|
|
75
|
+
// Resolve the Better Auth URL (explicit config, or derived from host/port)
|
|
76
|
+
const betterAuthUrl = config?.auth.betterAuthUrl || serverUrl;
|
|
77
|
+
// Build environment variables for the server process
|
|
78
|
+
const serverEnv = {
|
|
79
|
+
...process.env,
|
|
80
|
+
BETTER_AUTH_URL: betterAuthUrl,
|
|
81
|
+
BETTER_AUTH_TRUSTED_ORIGINS: process.env.BETTER_AUTH_TRUSTED_ORIGINS || trustedOrigins,
|
|
82
|
+
};
|
|
83
|
+
// Auth method configuration
|
|
84
|
+
if (config?.auth.method) {
|
|
85
|
+
serverEnv.AUTH_METHOD = config.auth.method;
|
|
86
|
+
}
|
|
87
|
+
// Keycloak OAuth configuration
|
|
88
|
+
if (config?.auth.keycloak) {
|
|
89
|
+
serverEnv.KEYCLOAK_CLIENT_ID = config.auth.keycloak.clientId;
|
|
90
|
+
serverEnv.KEYCLOAK_CLIENT_SECRET = config.auth.keycloak.clientSecret;
|
|
91
|
+
serverEnv.KEYCLOAK_ISSUER = config.auth.keycloak.issuer;
|
|
92
|
+
}
|
|
65
93
|
// Check if already running
|
|
66
94
|
const existingPid = getPid();
|
|
67
95
|
if (existingPid && isRunning(existingPid)) {
|
|
@@ -74,6 +102,7 @@ export async function startServer(options = {}) {
|
|
|
74
102
|
const child = spawn(binaryPath, [], {
|
|
75
103
|
stdio: 'inherit',
|
|
76
104
|
detached: false,
|
|
105
|
+
env: serverEnv,
|
|
77
106
|
});
|
|
78
107
|
child.on('error', (error) => {
|
|
79
108
|
reject(new Error(`Failed to start server: ${error.message}`));
|
|
@@ -94,7 +123,7 @@ export async function startServer(options = {}) {
|
|
|
94
123
|
const child = spawn(binaryPath, [], {
|
|
95
124
|
stdio: ['ignore', logFd, logFd], // Use file descriptor, not stream
|
|
96
125
|
detached: true,
|
|
97
|
-
env:
|
|
126
|
+
env: serverEnv,
|
|
98
127
|
});
|
|
99
128
|
// Close the file descriptor in parent - child has its own copy
|
|
100
129
|
closeSync(logFd);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kontexted",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "CLI tool for Kontexted - MCP proxy, workspaces management, and local server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"typescript": "^5.6.0"
|
|
44
44
|
},
|
|
45
45
|
"optionalDependencies": {
|
|
46
|
-
"@kontexted/darwin-arm64": "0.1.
|
|
47
|
-
"@kontexted/linux-x64": "0.1.
|
|
48
|
-
"@kontexted/windows-x64": "0.1.
|
|
46
|
+
"@kontexted/darwin-arm64": "0.1.8",
|
|
47
|
+
"@kontexted/linux-x64": "0.1.8",
|
|
48
|
+
"@kontexted/windows-x64": "0.1.8"
|
|
49
49
|
}
|
|
50
50
|
}
|