kontexted 0.1.5

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 (78) 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 +125 -0
  12. package/dist/commands/server/init.d.ts +6 -0
  13. package/dist/commands/server/init.js +112 -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/migrate.d.ts +4 -0
  17. package/dist/commands/server/migrate.js +29 -0
  18. package/dist/commands/server/show-invite.d.ts +4 -0
  19. package/dist/commands/server/show-invite.js +29 -0
  20. package/dist/commands/server/start.d.ts +6 -0
  21. package/dist/commands/server/start.js +44 -0
  22. package/dist/commands/server/status.d.ts +4 -0
  23. package/dist/commands/server/status.js +23 -0
  24. package/dist/commands/server/stop.d.ts +6 -0
  25. package/dist/commands/server/stop.js +32 -0
  26. package/dist/commands/show-config.d.ts +5 -0
  27. package/dist/commands/show-config.js +19 -0
  28. package/dist/commands/skill.d.ts +5 -0
  29. package/dist/commands/skill.js +211 -0
  30. package/dist/index.d.ts +1 -0
  31. package/dist/index.js +25 -0
  32. package/dist/lib/api-client.d.ts +36 -0
  33. package/dist/lib/api-client.js +130 -0
  34. package/dist/lib/config.d.ts +17 -0
  35. package/dist/lib/config.js +46 -0
  36. package/dist/lib/index.d.ts +6 -0
  37. package/dist/lib/index.js +6 -0
  38. package/dist/lib/logger.d.ts +24 -0
  39. package/dist/lib/logger.js +76 -0
  40. package/dist/lib/mcp-client.d.ts +14 -0
  41. package/dist/lib/mcp-client.js +62 -0
  42. package/dist/lib/oauth.d.ts +42 -0
  43. package/dist/lib/oauth.js +383 -0
  44. package/dist/lib/profile.d.ts +37 -0
  45. package/dist/lib/profile.js +49 -0
  46. package/dist/lib/proxy-server.d.ts +12 -0
  47. package/dist/lib/proxy-server.js +131 -0
  48. package/dist/lib/server/binary.d.ts +32 -0
  49. package/dist/lib/server/binary.js +127 -0
  50. package/dist/lib/server/config.d.ts +57 -0
  51. package/dist/lib/server/config.js +136 -0
  52. package/dist/lib/server/constants.d.ts +29 -0
  53. package/dist/lib/server/constants.js +35 -0
  54. package/dist/lib/server/daemon.d.ts +34 -0
  55. package/dist/lib/server/daemon.js +199 -0
  56. package/dist/lib/server/index.d.ts +5 -0
  57. package/dist/lib/server/index.js +5 -0
  58. package/dist/lib/server/migrate.d.ts +9 -0
  59. package/dist/lib/server/migrate.js +51 -0
  60. package/dist/lib/server-url.d.ts +8 -0
  61. package/dist/lib/server-url.js +25 -0
  62. package/dist/skill-init/index.d.ts +3 -0
  63. package/dist/skill-init/index.js +3 -0
  64. package/dist/skill-init/providers/base.d.ts +26 -0
  65. package/dist/skill-init/providers/base.js +1 -0
  66. package/dist/skill-init/providers/index.d.ts +13 -0
  67. package/dist/skill-init/providers/index.js +17 -0
  68. package/dist/skill-init/providers/opencode.d.ts +5 -0
  69. package/dist/skill-init/providers/opencode.js +48 -0
  70. package/dist/skill-init/templates/index.d.ts +3 -0
  71. package/dist/skill-init/templates/index.js +3 -0
  72. package/dist/skill-init/templates/kontexted-cli.d.ts +2 -0
  73. package/dist/skill-init/templates/kontexted-cli.js +169 -0
  74. package/dist/skill-init/utils.d.ts +66 -0
  75. package/dist/skill-init/utils.js +122 -0
  76. package/dist/types/index.d.ts +67 -0
  77. package/dist/types/index.js +4 -0
  78. package/package.json +50 -0
@@ -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/rabbyte-tech/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;
@@ -0,0 +1,19 @@
1
+ import { readConfig, getConfigPath } from "../lib/config.js";
2
+ /**
3
+ * Register the show-config command
4
+ */
5
+ export function registerShowConfigCommand(program) {
6
+ program
7
+ .command("show-config")
8
+ .description("Display all stored profiles")
9
+ .action(async () => {
10
+ const config = await readConfig();
11
+ console.log(`Config file: ${getConfigPath()}`);
12
+ console.log("");
13
+ if (Object.keys(config.profiles).length === 0) {
14
+ console.log("No profiles configured.");
15
+ return;
16
+ }
17
+ console.log(JSON.stringify(config, null, 2));
18
+ });
19
+ }
@@ -0,0 +1,5 @@
1
+ import type { Command } from "commander";
2
+ /**
3
+ * Register the skill command and its subcommands
4
+ */
5
+ export declare function registerSkillCommand(program: Command): void;
@@ -0,0 +1,211 @@
1
+ import * as readline from "readline";
2
+ import { readConfig, writeConfig } from "../lib/config.js";
3
+ import { getProfile } from "../lib/profile.js";
4
+ import { ApiClient } from "../lib/api-client.js";
5
+ import { ensureValidTokens } from "../lib/oauth.js";
6
+ import { getProvider, allTemplates } from "../skill-init/index.js";
7
+ import { initSkill } from "../skill-init/utils.js";
8
+ /**
9
+ * Execute workspace-tree skill via the API
10
+ */
11
+ async function executeWorkspaceTree(client, workspaceSlug) {
12
+ const response = await client.post("/api/skill/workspace-tree", { workspaceSlug });
13
+ if (!response.ok) {
14
+ const errorText = await response.text();
15
+ throw new Error(`Workspace tree skill failed: ${response.status} ${errorText}`);
16
+ }
17
+ return response.json();
18
+ }
19
+ /**
20
+ * Execute search-notes skill via the API
21
+ */
22
+ async function executeSearchNotes(client, workspaceSlug, query, limit) {
23
+ const body = { workspaceSlug, query };
24
+ if (limit !== undefined) {
25
+ body.limit = limit;
26
+ }
27
+ const response = await client.post("/api/skill/search-notes", body);
28
+ if (!response.ok) {
29
+ const errorText = await response.text();
30
+ throw new Error(`Search notes skill failed: ${response.status} ${errorText}`);
31
+ }
32
+ return response.json();
33
+ }
34
+ /**
35
+ * Execute note-by-id skill via the API
36
+ */
37
+ async function executeNoteById(client, workspaceSlug, notePublicId) {
38
+ const response = await client.post("/api/skill/note-by-id", {
39
+ workspaceSlug,
40
+ notePublicId
41
+ });
42
+ if (!response.ok) {
43
+ const errorText = await response.text();
44
+ throw new Error(`Note by ID skill failed: ${response.status} ${errorText}`);
45
+ }
46
+ return response.json();
47
+ }
48
+ /**
49
+ * Helper function to create an API client from a profile alias
50
+ */
51
+ async function createApiClient(alias) {
52
+ const config = await readConfig();
53
+ const profile = getProfile(config, alias);
54
+ if (!profile) {
55
+ console.error(`Profile not found: ${alias}. Run 'kontexted login' first.`);
56
+ process.exit(1);
57
+ }
58
+ // Proactively refresh token if needed (non-interactive)
59
+ const tokensValid = await ensureValidTokens(profile.oauth, async () => writeConfig(config), profile.serverUrl);
60
+ if (!tokensValid) {
61
+ console.error(`Authentication expired. Run 'kontexted login --alias ${alias}' to re-authenticate.`);
62
+ process.exit(1);
63
+ }
64
+ return new ApiClient(profile.serverUrl, profile.oauth, async () => writeConfig(config));
65
+ }
66
+ /**
67
+ * Display results from a skill execution
68
+ */
69
+ function displayResult(result) {
70
+ console.log(JSON.stringify(result, null, 2));
71
+ }
72
+ /**
73
+ * Register the skill command and its subcommands
74
+ */
75
+ export function registerSkillCommand(program) {
76
+ const skillCommand = program
77
+ .command("skill")
78
+ .description("Invoke LLM skill via CLI");
79
+ skillCommand
80
+ .command("workspace-tree")
81
+ .description("Get the workspace tree structure")
82
+ .requiredOption("--alias <name>", "Profile alias to use")
83
+ .action(async (options) => {
84
+ try {
85
+ const client = await createApiClient(options.alias);
86
+ const config = await readConfig();
87
+ const profile = getProfile(config, options.alias);
88
+ if (!profile) {
89
+ console.error(`Profile not found: ${options.alias}. Run 'kontexted login' first.`);
90
+ process.exit(1);
91
+ }
92
+ const result = await executeWorkspaceTree(client, profile.workspace);
93
+ displayResult(result);
94
+ }
95
+ catch (error) {
96
+ console.error(error instanceof Error ? error.message : String(error));
97
+ process.exit(1);
98
+ }
99
+ });
100
+ skillCommand
101
+ .command("search-notes")
102
+ .description("Search notes by query in a workspace")
103
+ .requiredOption("--alias <name>", "Profile alias to use")
104
+ .requiredOption("--query <text>", "Search query")
105
+ .option("--limit <number>", "Maximum number of results (default: 20, max: 50)", parseInt)
106
+ .action(async (options) => {
107
+ try {
108
+ const client = await createApiClient(options.alias);
109
+ const config = await readConfig();
110
+ const profile = getProfile(config, options.alias);
111
+ if (!profile) {
112
+ console.error(`Profile not found: ${options.alias}. Run 'kontexted login' first.`);
113
+ process.exit(1);
114
+ }
115
+ const result = await executeSearchNotes(client, profile.workspace, options.query, options.limit);
116
+ displayResult(result);
117
+ }
118
+ catch (error) {
119
+ console.error(error instanceof Error ? error.message : String(error));
120
+ process.exit(1);
121
+ }
122
+ });
123
+ skillCommand
124
+ .command("note-by-id")
125
+ .description("Get a specific note by its public ID")
126
+ .requiredOption("--alias <name>", "Profile alias to use")
127
+ .requiredOption("--note-id <id>", "Public ID of the note")
128
+ .action(async (options) => {
129
+ try {
130
+ const client = await createApiClient(options.alias);
131
+ const config = await readConfig();
132
+ const profile = getProfile(config, options.alias);
133
+ if (!profile) {
134
+ console.error(`Profile not found: ${options.alias}. Run 'kontexted login' first.`);
135
+ process.exit(1);
136
+ }
137
+ const result = await executeNoteById(client, profile.workspace, options.noteId);
138
+ displayResult(result);
139
+ }
140
+ catch (error) {
141
+ console.error(error instanceof Error ? error.message : String(error));
142
+ process.exit(1);
143
+ }
144
+ });
145
+ skillCommand
146
+ .command("init")
147
+ .description("Initialize AI agent skills for the current project")
148
+ .option("--provider <name>", "Provider to use (default: opencode)", "opencode")
149
+ .option("--all", "Generate all available skills without prompting", false)
150
+ .action(async (options) => {
151
+ try {
152
+ // Get the provider
153
+ let provider;
154
+ try {
155
+ provider = getProvider(options.provider);
156
+ }
157
+ catch {
158
+ console.error(`Unknown skill provider: ${options.provider}`);
159
+ console.error(`Available providers: ${["opencode"].join(", ")}`);
160
+ process.exit(1);
161
+ }
162
+ // Show what will be generated
163
+ console.log(`This will generate the following skills for ${provider.name}:`);
164
+ for (const template of allTemplates) {
165
+ const skillPath = provider.getSkillPath(template.name);
166
+ console.log(` - ${template.name} → ${skillPath}`);
167
+ }
168
+ // Check if we should prompt for confirmation
169
+ if (!options.all) {
170
+ const rl = readline.createInterface({
171
+ input: process.stdin,
172
+ output: process.stdout,
173
+ });
174
+ const answer = await new Promise((resolve) => {
175
+ rl.question("\nContinue? (y/N) ", (response) => {
176
+ rl.close();
177
+ resolve(response);
178
+ });
179
+ });
180
+ if (answer.toLowerCase() !== "y") {
181
+ console.log("Aborted.");
182
+ process.exit(0);
183
+ }
184
+ }
185
+ // Generate all skills
186
+ const results = [];
187
+ for (const template of allTemplates) {
188
+ console.log(`Generating skill: ${template.name}`);
189
+ const result = await initSkill({
190
+ skill: template,
191
+ provider,
192
+ });
193
+ const status = result.created ? "Created" : "Updated";
194
+ console.log(`✓ ${status} ${result.path}`);
195
+ results.push({
196
+ name: result.name,
197
+ path: result.path,
198
+ created: result.created,
199
+ });
200
+ }
201
+ // Show summary
202
+ const created = results.filter((r) => r.created).length;
203
+ const updated = results.length - created;
204
+ console.log(`\nSummary: ${created} created, ${updated} updated`);
205
+ }
206
+ catch (error) {
207
+ console.error(error instanceof Error ? error.message : String(error));
208
+ process.exit(1);
209
+ }
210
+ });
211
+ }
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { registerLoginCommand } from "./commands/login.js";
4
+ import { registerLogoutCommand } from "./commands/logout.js";
5
+ import { registerShowConfigCommand } from "./commands/show-config.js";
6
+ import { registerMcpCommand } from "./commands/mcp.js";
7
+ import { registerSkillCommand } from "./commands/skill.js";
8
+ import { registerServerCommand } from "./commands/server/index.js";
9
+ const program = new Command();
10
+ program
11
+ .name("kontexted")
12
+ .description("CLI tool for Kontexted - MCP proxy and workspace management")
13
+ .version("0.1.0");
14
+ // Register subcommands
15
+ registerLoginCommand(program);
16
+ registerLogoutCommand(program);
17
+ registerShowConfigCommand(program);
18
+ registerSkillCommand(program);
19
+ registerMcpCommand(program);
20
+ registerServerCommand(program);
21
+ // Parse arguments
22
+ program.parseAsync(process.argv).catch((error) => {
23
+ console.error(error instanceof Error ? error.message : String(error));
24
+ process.exit(1);
25
+ });
@@ -0,0 +1,36 @@
1
+ import type { OAuthState } from "../types/index.js";
2
+ /**
3
+ * API client for making authenticated HTTP requests with automatic token refresh
4
+ */
5
+ export declare class ApiClient {
6
+ private serverUrl;
7
+ private oauth;
8
+ private persist;
9
+ constructor(serverUrl: string, oauth: OAuthState, persist: () => Promise<void>);
10
+ /**
11
+ * Make an authenticated HTTP request
12
+ * Automatically handles token refresh on 401 responses
13
+ */
14
+ request(path: string, options?: RequestInit): Promise<Response>;
15
+ /**
16
+ * Refresh the access token using the refresh token
17
+ * @returns true if refresh was successful, false otherwise
18
+ */
19
+ private refreshToken;
20
+ /**
21
+ * Make a GET request
22
+ */
23
+ get(path: string): Promise<Response>;
24
+ /**
25
+ * Make a POST request with a JSON body
26
+ */
27
+ post(path: string, body: unknown): Promise<Response>;
28
+ /**
29
+ * Make a PUT request with a JSON body
30
+ */
31
+ put(path: string, body: unknown): Promise<Response>;
32
+ /**
33
+ * Make a DELETE request
34
+ */
35
+ delete(path: string): Promise<Response>;
36
+ }
@@ -0,0 +1,130 @@
1
+ import { logDebug, logError } from "../lib/logger.js";
2
+ /**
3
+ * API client for making authenticated HTTP requests with automatic token refresh
4
+ */
5
+ export class ApiClient {
6
+ serverUrl;
7
+ oauth;
8
+ persist;
9
+ constructor(serverUrl, oauth, persist) {
10
+ this.serverUrl = serverUrl;
11
+ this.oauth = oauth;
12
+ this.persist = persist;
13
+ }
14
+ /**
15
+ * Make an authenticated HTTP request
16
+ * Automatically handles token refresh on 401 responses
17
+ */
18
+ async request(path, options = {}) {
19
+ const url = new URL(path, this.serverUrl);
20
+ // Prepare headers with Authorization
21
+ const headers = {
22
+ ...options.headers,
23
+ Authorization: `Bearer ${this.oauth.tokens?.access_token}`,
24
+ };
25
+ // Set Content-Type to application/json by default for methods that have a body
26
+ if (options.body !== undefined && !headers["Content-Type"]) {
27
+ headers["Content-Type"] = "application/json";
28
+ }
29
+ const requestOptions = {
30
+ ...options,
31
+ headers,
32
+ };
33
+ logDebug(`[API CLIENT] ${options.method ?? "GET"} ${path}`);
34
+ let response = await fetch(url.toString(), requestOptions);
35
+ logDebug(`[API CLIENT] Response status: ${response.status}`);
36
+ // Handle 401 Unauthorized - attempt to refresh token
37
+ if (response.status === 401 && this.oauth.tokens?.refresh_token) {
38
+ logDebug("[API CLIENT] Token expired, attempting to refresh...");
39
+ const refreshed = await this.refreshToken();
40
+ if (refreshed) {
41
+ logDebug("[API CLIENT] Token refreshed successfully, retrying request...");
42
+ // Update Authorization header with new token
43
+ headers.Authorization = `Bearer ${this.oauth.tokens?.access_token}`;
44
+ requestOptions.headers = headers;
45
+ // Retry the original request with new token
46
+ response = await fetch(url.toString(), requestOptions);
47
+ logDebug(`[API CLIENT] Retry response status: ${response.status}`);
48
+ }
49
+ else {
50
+ throw new Error("Failed to refresh access token. Please run 'kontexted login' to re-authenticate.");
51
+ }
52
+ }
53
+ // If still 401 after refresh attempt (or no refresh token available)
54
+ if (response.status === 401) {
55
+ throw new Error("Authentication failed. Please run 'kontexted login' to re-authenticate.");
56
+ }
57
+ return response;
58
+ }
59
+ /**
60
+ * Refresh the access token using the refresh token
61
+ * @returns true if refresh was successful, false otherwise
62
+ */
63
+ async refreshToken() {
64
+ if (!this.oauth.tokens?.refresh_token) {
65
+ logError("[API CLIENT] No refresh token available");
66
+ return false;
67
+ }
68
+ try {
69
+ const tokenUrl = new URL("/api/auth/oauth2/token", new URL(this.serverUrl).origin);
70
+ logDebug(`[API CLIENT] Refreshing token - URL: ${tokenUrl.toString()}`);
71
+ const response = await fetch(tokenUrl.toString(), {
72
+ method: "POST",
73
+ headers: {
74
+ "Content-Type": "application/x-www-form-urlencoded",
75
+ },
76
+ body: new URLSearchParams({
77
+ grant_type: "refresh_token",
78
+ refresh_token: this.oauth.tokens.refresh_token,
79
+ client_id: this.oauth.clientInformation?.client_id ?? "",
80
+ client_secret: this.oauth.clientInformation?.client_secret ?? "",
81
+ }),
82
+ });
83
+ logDebug(`[API CLIENT] Token refresh response status: ${response.status}`);
84
+ if (!response.ok) {
85
+ const errorText = await response.text();
86
+ logError(`[API CLIENT] Failed to refresh access token - Status: ${response.status}, Error: ${errorText}`);
87
+ return false;
88
+ }
89
+ const tokens = (await response.json());
90
+ this.oauth.tokens = tokens;
91
+ await this.persist();
92
+ logDebug("[API CLIENT] Token refresh successful");
93
+ return true;
94
+ }
95
+ catch (error) {
96
+ logError("[API CLIENT] Error refreshing access token:", error);
97
+ return false;
98
+ }
99
+ }
100
+ /**
101
+ * Make a GET request
102
+ */
103
+ async get(path) {
104
+ return this.request(path, { method: "GET" });
105
+ }
106
+ /**
107
+ * Make a POST request with a JSON body
108
+ */
109
+ async post(path, body) {
110
+ return this.request(path, {
111
+ method: "POST",
112
+ body: JSON.stringify(body),
113
+ });
114
+ }
115
+ /**
116
+ * Make a PUT request with a JSON body
117
+ */
118
+ async put(path, body) {
119
+ return this.request(path, {
120
+ method: "PUT",
121
+ body: JSON.stringify(body),
122
+ });
123
+ }
124
+ /**
125
+ * Make a DELETE request
126
+ */
127
+ async delete(path) {
128
+ return this.request(path, { method: "DELETE" });
129
+ }
130
+ }
@@ -0,0 +1,17 @@
1
+ import type { Config } from "../types/index.js";
2
+ /**
3
+ * Read the configuration file from disk
4
+ */
5
+ export declare function readConfig(): Promise<Config>;
6
+ /**
7
+ * Write configuration to disk
8
+ */
9
+ export declare function writeConfig(config: Config): Promise<void>;
10
+ /**
11
+ * Remove the entire config file
12
+ */
13
+ export declare function removeConfig(): Promise<void>;
14
+ /**
15
+ * Get the config file path (for display/debugging)
16
+ */
17
+ export declare function getConfigPath(): string;
@@ -0,0 +1,46 @@
1
+ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { dirname, join } from "node:path";
4
+ const CONFIG_DIR = join(homedir(), ".kontexted");
5
+ const CONFIG_PATH = join(CONFIG_DIR, "profile.json");
6
+ /**
7
+ * Read the configuration file from disk
8
+ */
9
+ export async function readConfig() {
10
+ try {
11
+ const raw = await readFile(CONFIG_PATH, "utf8");
12
+ const parsed = JSON.parse(raw);
13
+ if (!parsed || typeof parsed !== "object") {
14
+ return { profiles: {} };
15
+ }
16
+ return parsed.profiles ? { profiles: parsed.profiles } : { profiles: {} };
17
+ }
18
+ catch (error) {
19
+ if (error &&
20
+ typeof error === "object" &&
21
+ "code" in error &&
22
+ error.code === "ENOENT") {
23
+ return { profiles: {} };
24
+ }
25
+ throw error;
26
+ }
27
+ }
28
+ /**
29
+ * Write configuration to disk
30
+ */
31
+ export async function writeConfig(config) {
32
+ await mkdir(dirname(CONFIG_PATH), { recursive: true });
33
+ await writeFile(CONFIG_PATH, JSON.stringify(config, null, 2));
34
+ }
35
+ /**
36
+ * Remove the entire config file
37
+ */
38
+ export async function removeConfig() {
39
+ await rm(CONFIG_PATH, { force: true });
40
+ }
41
+ /**
42
+ * Get the config file path (for display/debugging)
43
+ */
44
+ export function getConfigPath() {
45
+ return CONFIG_PATH;
46
+ }
@@ -0,0 +1,6 @@
1
+ export * from './api-client.js';
2
+ export * from './config.js';
3
+ export * from './oauth.js';
4
+ export * from './mcp-client.js';
5
+ export * from './proxy-server.js';
6
+ export * from './server/index.js';
@@ -0,0 +1,6 @@
1
+ export * from './api-client.js';
2
+ export * from './config.js';
3
+ export * from './oauth.js';
4
+ export * from './mcp-client.js';
5
+ export * from './proxy-server.js';
6
+ export * from './server/index.js';
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Set whether logging is enabled
3
+ */
4
+ export declare function setLogEnabled(enabled: boolean): void;
5
+ /**
6
+ * Log an info message (file only)
7
+ */
8
+ export declare function logInfo(message: string, data?: unknown): void;
9
+ /**
10
+ * Log a debug message (file only)
11
+ */
12
+ export declare function logDebug(message: string, data?: unknown): void;
13
+ /**
14
+ * Log a warning message (file only)
15
+ */
16
+ export declare function logWarn(message: string, data?: unknown): void;
17
+ /**
18
+ * Log an error message (file only)
19
+ */
20
+ export declare function logError(message: string, data?: unknown): void;
21
+ /**
22
+ * Get the log file path
23
+ */
24
+ export declare function getLogFilePath(): string;