@exreve/exk 1.0.17 → 1.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agentSession.js +37 -5
- package/dist/index.js +93 -0
- package/dist/moduleMcpServer.js +17 -0
- package/dist/ttc-cli.tar.gz +0 -0
- package/package.json +1 -1
package/dist/agentSession.js
CHANGED
|
@@ -4,7 +4,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from '
|
|
|
4
4
|
import { symlink as fsSymlink } from 'fs';
|
|
5
5
|
import { getSkillContent } from './skills/index.js';
|
|
6
6
|
import { isLocalModel, unwrapModelName, startOpenAIAdapter, getAdapterConfig } from './openaiAdapter.js';
|
|
7
|
-
import { createModuleMcpServer } from './moduleMcpServer.js';
|
|
7
|
+
import { createModuleMcpServer, getModuleToolHint } from './moduleMcpServer.js';
|
|
8
8
|
import path from 'path';
|
|
9
9
|
import os from 'os';
|
|
10
10
|
import { createRequire } from 'module';
|
|
@@ -134,10 +134,11 @@ function loadAiConfig() {
|
|
|
134
134
|
const apiKey = typeof config.authToken === 'string' ? config.authToken.trim() : '';
|
|
135
135
|
const baseUrl = typeof config.baseUrl === 'string' ? config.baseUrl.trim() : '';
|
|
136
136
|
const model = typeof config.model === 'string' && config.model.trim() ? config.model.trim() : DEFAULT_AI_MODEL;
|
|
137
|
-
|
|
137
|
+
const proxy = typeof config.proxy === 'string' ? config.proxy.trim() : '';
|
|
138
|
+
return { apiKey, baseUrl, model, proxy };
|
|
138
139
|
}
|
|
139
140
|
catch {
|
|
140
|
-
return { apiKey: '', baseUrl: '', model: DEFAULT_AI_MODEL };
|
|
141
|
+
return { apiKey: '', baseUrl: '', model: DEFAULT_AI_MODEL, proxy: '' };
|
|
141
142
|
}
|
|
142
143
|
}
|
|
143
144
|
/** Create (or reuse) an empty directory to use as CLAUDE_CONFIG_DIR.
|
|
@@ -151,6 +152,17 @@ function getEmptyConfigDir() {
|
|
|
151
152
|
}
|
|
152
153
|
return configDir;
|
|
153
154
|
}
|
|
155
|
+
const PROXY_CONFIG_PATH = path.join(os.homedir(), '.talk-to-code', 'proxy.json');
|
|
156
|
+
/** Read proxy toggle state from disk (synchronous) */
|
|
157
|
+
function readProxyToggle() {
|
|
158
|
+
try {
|
|
159
|
+
const data = readFileSync(PROXY_CONFIG_PATH, 'utf-8');
|
|
160
|
+
return JSON.parse(data);
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return { enabled: false };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
154
166
|
/** Env for the Claude Code child: copy of host env with host ANTHROPIC_* stripped, then inject from ai-config only.
|
|
155
167
|
* If a local model is provided, override baseUrl to point to the anthropic-proxy adapter. */
|
|
156
168
|
function envForClaudeCodeChild(localModel) {
|
|
@@ -160,11 +172,24 @@ function envForClaudeCodeChild(localModel) {
|
|
|
160
172
|
delete env.ANTHROPIC_BASE_URL;
|
|
161
173
|
delete env.ANTHROPIC_AUTH_TOKEN;
|
|
162
174
|
// Inject from our ai-config.json only
|
|
163
|
-
const { apiKey, baseUrl } = loadAiConfig();
|
|
175
|
+
const { apiKey, baseUrl, proxy } = loadAiConfig();
|
|
164
176
|
if (apiKey)
|
|
165
177
|
env.ANTHROPIC_API_KEY = apiKey;
|
|
166
178
|
if (baseUrl)
|
|
167
179
|
env.ANTHROPIC_BASE_URL = baseUrl;
|
|
180
|
+
// Apply proxy if enabled
|
|
181
|
+
const proxyToggle = readProxyToggle();
|
|
182
|
+
if (proxyToggle.enabled && proxy) {
|
|
183
|
+
env.HTTPS_PROXY = proxy;
|
|
184
|
+
env.HTTP_PROXY = proxy;
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
// Clear any inherited proxy env
|
|
188
|
+
delete env.HTTPS_PROXY;
|
|
189
|
+
delete env.HTTP_PROXY;
|
|
190
|
+
delete env.https_proxy;
|
|
191
|
+
delete env.http_proxy;
|
|
192
|
+
}
|
|
168
193
|
// Prevent ~/.claude/settings.json env section from overriding our base URL.
|
|
169
194
|
// This redirects the Claude config dir to an empty dir so that
|
|
170
195
|
// ~/.claude/settings.json (which may have ANTHROPIC_BASE_URL set to z.ai)
|
|
@@ -418,7 +443,14 @@ export class AgentSessionManager {
|
|
|
418
443
|
// Create a fresh MCP server for each query call (SDK connects transport internally, cannot reuse)
|
|
419
444
|
...(() => {
|
|
420
445
|
const mcpServer = this.buildMcpServer(sessionId);
|
|
421
|
-
|
|
446
|
+
if (mcpServer) {
|
|
447
|
+
const toolHint = getModuleToolHint(session.enabledModules || []);
|
|
448
|
+
return {
|
|
449
|
+
mcpServers: [mcpServer],
|
|
450
|
+
...(toolHint ? { systemPrompt: toolHint } : {})
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
return {};
|
|
422
454
|
})(),
|
|
423
455
|
...(pathToClaudeCodeExecutable ? { pathToClaudeCodeExecutable } : {}),
|
|
424
456
|
spawnClaudeCodeProcess: (spawnOptions) => {
|
package/dist/index.js
CHANGED
|
@@ -66,6 +66,33 @@ async function fetchAiConfig(authToken) {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
const AI_CONFIG_FILE = path.join(CONFIG_DIR, 'ai-config.json');
|
|
69
|
+
const PROXY_CONFIG_FILE = path.join(CONFIG_DIR, 'proxy.json');
|
|
70
|
+
/** Read proxy toggle state from disk */
|
|
71
|
+
async function readProxyConfig() {
|
|
72
|
+
try {
|
|
73
|
+
const raw = await fs.readFile(PROXY_CONFIG_FILE, 'utf-8');
|
|
74
|
+
return JSON.parse(raw);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return { enabled: false };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** Write proxy toggle state to disk */
|
|
81
|
+
async function writeProxyConfig(cfg) {
|
|
82
|
+
await fs.mkdir(CONFIG_DIR, { recursive: true });
|
|
83
|
+
await fs.writeFile(PROXY_CONFIG_FILE, JSON.stringify(cfg, null, 2));
|
|
84
|
+
}
|
|
85
|
+
/** Get the proxy URL from ai-config.json (saved from backend) */
|
|
86
|
+
function getProxyUrl() {
|
|
87
|
+
try {
|
|
88
|
+
const raw = fsSync.readFileSync(AI_CONFIG_FILE, 'utf-8');
|
|
89
|
+
const j = JSON.parse(raw);
|
|
90
|
+
return typeof j.proxy === 'string' ? j.proxy.trim() : '';
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return '';
|
|
94
|
+
}
|
|
95
|
+
}
|
|
69
96
|
/** True if ai-config.json has a model API key (not read from host ANTHROPIC_* env). */
|
|
70
97
|
function hasAiCredentials() {
|
|
71
98
|
try {
|
|
@@ -1796,6 +1823,39 @@ async function runDaemon(foreground = false, email) {
|
|
|
1796
1823
|
});
|
|
1797
1824
|
});
|
|
1798
1825
|
// Cloudflared handlers
|
|
1826
|
+
// Proxy toggle handler
|
|
1827
|
+
socket.on('proxy:toggle:request', async (data, callback) => {
|
|
1828
|
+
try {
|
|
1829
|
+
const { enable } = data;
|
|
1830
|
+
const proxyUrl = getProxyUrl();
|
|
1831
|
+
if (enable && !proxyUrl) {
|
|
1832
|
+
callback?.({ success: false, enabled: false });
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1835
|
+
await writeProxyConfig({ enabled: enable });
|
|
1836
|
+
if (foreground) {
|
|
1837
|
+
console.log(`[CLI] Proxy ${enable ? 'enabled' : 'disabled'}${proxyUrl ? `: ${proxyUrl}` : ''}`);
|
|
1838
|
+
}
|
|
1839
|
+
else {
|
|
1840
|
+
console.log(`Proxy ${enable ? 'enabled' : 'disabled'}`);
|
|
1841
|
+
}
|
|
1842
|
+
callback?.({ success: true, enabled: enable, proxyUrl: enable ? proxyUrl : undefined });
|
|
1843
|
+
}
|
|
1844
|
+
catch (error) {
|
|
1845
|
+
callback?.({ success: false, enabled: false });
|
|
1846
|
+
}
|
|
1847
|
+
});
|
|
1848
|
+
// Proxy status handler
|
|
1849
|
+
socket.on('proxy:status:request', async (_data, callback) => {
|
|
1850
|
+
try {
|
|
1851
|
+
const proxyConfig = await readProxyConfig();
|
|
1852
|
+
const proxyUrl = getProxyUrl();
|
|
1853
|
+
callback?.({ enabled: proxyConfig.enabled, proxyUrl: proxyConfig.enabled ? proxyUrl : undefined });
|
|
1854
|
+
}
|
|
1855
|
+
catch {
|
|
1856
|
+
callback?.({ enabled: false });
|
|
1857
|
+
}
|
|
1858
|
+
});
|
|
1799
1859
|
socket.on('cloudflared:check:request', async () => {
|
|
1800
1860
|
try {
|
|
1801
1861
|
let installed = false;
|
|
@@ -2779,4 +2839,37 @@ program
|
|
|
2779
2839
|
process.exit(1);
|
|
2780
2840
|
});
|
|
2781
2841
|
});
|
|
2842
|
+
// Enable proxy command
|
|
2843
|
+
program
|
|
2844
|
+
.command('enable')
|
|
2845
|
+
.description('Enable a feature (e.g. proxy)')
|
|
2846
|
+
.argument('<feature>', 'Feature to enable (proxy)')
|
|
2847
|
+
.action(async (feature) => {
|
|
2848
|
+
if (feature !== 'proxy') {
|
|
2849
|
+
console.error(`Unknown feature: ${feature}. Available: proxy`);
|
|
2850
|
+
process.exit(1);
|
|
2851
|
+
}
|
|
2852
|
+
const proxyUrl = getProxyUrl();
|
|
2853
|
+
if (!proxyUrl) {
|
|
2854
|
+
console.log('No proxy URL configured. Run "exk daemon" first to sync config from server.');
|
|
2855
|
+
process.exit(1);
|
|
2856
|
+
}
|
|
2857
|
+
await writeProxyConfig({ enabled: true });
|
|
2858
|
+
console.log(`Proxy enabled: ${proxyUrl}`);
|
|
2859
|
+
process.exit(0);
|
|
2860
|
+
});
|
|
2861
|
+
// Disable proxy command
|
|
2862
|
+
program
|
|
2863
|
+
.command('disable')
|
|
2864
|
+
.description('Disable a feature (e.g. proxy)')
|
|
2865
|
+
.argument('<feature>', 'Feature to disable (proxy)')
|
|
2866
|
+
.action(async (feature) => {
|
|
2867
|
+
if (feature !== 'proxy') {
|
|
2868
|
+
console.error(`Unknown feature: ${feature}. Available: proxy`);
|
|
2869
|
+
process.exit(1);
|
|
2870
|
+
}
|
|
2871
|
+
await writeProxyConfig({ enabled: false });
|
|
2872
|
+
console.log('Proxy disabled');
|
|
2873
|
+
process.exit(0);
|
|
2874
|
+
});
|
|
2782
2875
|
program.parse();
|
package/dist/moduleMcpServer.js
CHANGED
|
@@ -91,3 +91,20 @@ export function createModuleMcpServer(config) {
|
|
|
91
91
|
});
|
|
92
92
|
return server;
|
|
93
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Get a system prompt hint describing available module tools.
|
|
96
|
+
* This ensures the model knows about custom MCP tools upfront without
|
|
97
|
+
* having to discover them through the MCP tool-listing mechanism.
|
|
98
|
+
*/
|
|
99
|
+
export function getModuleToolHint(enabledModules) {
|
|
100
|
+
if (enabledModules.length === 0)
|
|
101
|
+
return null;
|
|
102
|
+
const toolDescriptions = [];
|
|
103
|
+
if (enabledModules.includes('user-choice')) {
|
|
104
|
+
toolDescriptions.push('- user_choice_request: Request user input when making decisions. Presents a modal to the user with options and waits for their response. Use this when you need the user to choose between options or confirm an action.');
|
|
105
|
+
}
|
|
106
|
+
// Add more module tool descriptions here as they are implemented
|
|
107
|
+
if (toolDescriptions.length === 0)
|
|
108
|
+
return null;
|
|
109
|
+
return `You have access to the following custom MCP tools:\n${toolDescriptions.join('\n')}\n\nUse these tools proactively when they are relevant to the task.`;
|
|
110
|
+
}
|
package/dist/ttc-cli.tar.gz
CHANGED
|
Binary file
|