@ekkos/cli 0.2.17 → 0.2.18
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/commands/setup.js
CHANGED
|
@@ -10,6 +10,7 @@ const fs_1 = require("fs");
|
|
|
10
10
|
const chalk_1 = __importDefault(require("chalk"));
|
|
11
11
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
12
12
|
const ora_1 = __importDefault(require("ora"));
|
|
13
|
+
const hooks_js_1 = require("./hooks.js");
|
|
13
14
|
const EKKOS_API_URL = 'https://mcp.ekkos.dev';
|
|
14
15
|
const CONFIG_DIR = (0, path_1.join)((0, os_1.homedir)(), '.ekkos');
|
|
15
16
|
const CONFIG_FILE = (0, path_1.join)(CONFIG_DIR, 'config.json');
|
|
@@ -207,24 +208,74 @@ async function setupIDE(ide, apiKey, config) {
|
|
|
207
208
|
async function setupClaudeCode(apiKey) {
|
|
208
209
|
const claudeDir = (0, path_1.join)((0, os_1.homedir)(), '.claude');
|
|
209
210
|
const hooksDir = (0, path_1.join)(claudeDir, 'hooks');
|
|
210
|
-
|
|
211
|
-
|
|
211
|
+
const stateDir = (0, path_1.join)(claudeDir, 'state');
|
|
212
|
+
// Create directories
|
|
213
|
+
(0, fs_1.mkdirSync)(claudeDir, { recursive: true });
|
|
214
|
+
(0, fs_1.mkdirSync)(hooksDir, { recursive: true });
|
|
215
|
+
(0, fs_1.mkdirSync)(stateDir, { recursive: true });
|
|
216
|
+
// Check for existing custom hooks (don't have EKKOS_MANAGED=1 marker)
|
|
217
|
+
const isWindows = (0, os_1.platform)() === 'win32';
|
|
218
|
+
const hookExt = isWindows ? '.ps1' : '.sh';
|
|
219
|
+
const hookFiles = ['user-prompt-submit', 'stop', 'session-start', 'assistant-response'];
|
|
220
|
+
let hasCustomHooks = false;
|
|
221
|
+
for (const hookName of hookFiles) {
|
|
222
|
+
const hookPath = (0, path_1.join)(hooksDir, `${hookName}${hookExt}`);
|
|
223
|
+
if ((0, fs_1.existsSync)(hookPath)) {
|
|
224
|
+
const content = (0, fs_1.readFileSync)(hookPath, 'utf-8');
|
|
225
|
+
if (!content.includes('EKKOS_MANAGED=1')) {
|
|
226
|
+
hasCustomHooks = true;
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (hasCustomHooks) {
|
|
232
|
+
// User has custom hooks - don't overwrite, use minimal approach
|
|
233
|
+
console.log(chalk_1.default.yellow(' Detected custom hooks - preserving your hooks'));
|
|
234
|
+
console.log(chalk_1.default.gray(' Run `ekkos hooks install --global` to upgrade to managed hooks'));
|
|
235
|
+
console.log(chalk_1.default.gray(' (This will overwrite existing hooks with full-featured versions)'));
|
|
236
|
+
// Still save API key for existing hooks to use
|
|
212
237
|
}
|
|
238
|
+
else {
|
|
239
|
+
// No custom hooks OR all managed - safe to install full templates
|
|
240
|
+
try {
|
|
241
|
+
await (0, hooks_js_1.hooksInstall)({ global: true, verbose: false });
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
// Fallback: if manifest-driven install fails, generate basic hooks
|
|
245
|
+
console.log(chalk_1.default.yellow(' Note: Could not install hooks from templates'));
|
|
246
|
+
console.log(chalk_1.default.gray(' Generating basic hooks instead...'));
|
|
247
|
+
await generateBasicHooks(hooksDir, apiKey);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// Save API key to config for hooks to use
|
|
251
|
+
const ekkosConfigDir = (0, path_1.join)((0, os_1.homedir)(), '.ekkos');
|
|
252
|
+
(0, fs_1.mkdirSync)(ekkosConfigDir, { recursive: true });
|
|
253
|
+
const configPath = (0, path_1.join)(ekkosConfigDir, 'config.json');
|
|
254
|
+
let existingConfig = {};
|
|
255
|
+
if ((0, fs_1.existsSync)(configPath)) {
|
|
256
|
+
try {
|
|
257
|
+
existingConfig = JSON.parse((0, fs_1.readFileSync)(configPath, 'utf-8'));
|
|
258
|
+
}
|
|
259
|
+
catch { }
|
|
260
|
+
}
|
|
261
|
+
// Update config with API key (hookApiKey for hooks, apiKey for compatibility)
|
|
262
|
+
existingConfig.hookApiKey = apiKey;
|
|
263
|
+
existingConfig.apiKey = apiKey;
|
|
264
|
+
existingConfig.updatedAt = new Date().toISOString();
|
|
265
|
+
(0, fs_1.writeFileSync)(configPath, JSON.stringify(existingConfig, null, 2));
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Generate basic inline hooks as fallback when templates aren't available
|
|
269
|
+
*/
|
|
270
|
+
async function generateBasicHooks(hooksDir, apiKey) {
|
|
213
271
|
const isWindows = (0, os_1.platform)() === 'win32';
|
|
214
272
|
if (isWindows) {
|
|
215
|
-
// Windows: PowerShell hooks
|
|
216
273
|
const promptSubmitHook = generatePromptSubmitHookPS(apiKey);
|
|
217
|
-
|
|
218
|
-
(0, fs_1.writeFileSync)(promptSubmitPath, promptSubmitHook);
|
|
274
|
+
(0, fs_1.writeFileSync)((0, path_1.join)(hooksDir, 'user-prompt-submit.ps1'), promptSubmitHook);
|
|
219
275
|
const stopHook = generateStopHookPS(apiKey);
|
|
220
|
-
|
|
221
|
-
(0, fs_1.writeFileSync)(stopPath, stopHook);
|
|
222
|
-
// Create wrapper batch files for Windows
|
|
223
|
-
(0, fs_1.writeFileSync)((0, path_1.join)(hooksDir, 'user-prompt-submit.cmd'), `@echo off\npowershell -ExecutionPolicy Bypass -File "%~dp0user-prompt-submit.ps1"`);
|
|
224
|
-
(0, fs_1.writeFileSync)((0, path_1.join)(hooksDir, 'stop.cmd'), `@echo off\npowershell -ExecutionPolicy Bypass -File "%~dp0stop.ps1"`);
|
|
276
|
+
(0, fs_1.writeFileSync)((0, path_1.join)(hooksDir, 'stop.ps1'), stopHook);
|
|
225
277
|
}
|
|
226
278
|
else {
|
|
227
|
-
// Unix: Bash hooks
|
|
228
279
|
const promptSubmitHook = generatePromptSubmitHook(apiKey);
|
|
229
280
|
const promptSubmitPath = (0, path_1.join)(hooksDir, 'user-prompt-submit.sh');
|
|
230
281
|
(0, fs_1.writeFileSync)(promptSubmitPath, promptSubmitHook);
|
|
@@ -234,11 +285,6 @@ async function setupClaudeCode(apiKey) {
|
|
|
234
285
|
(0, fs_1.writeFileSync)(stopPath, stopHook);
|
|
235
286
|
(0, fs_1.chmodSync)(stopPath, '755');
|
|
236
287
|
}
|
|
237
|
-
// Create state directory
|
|
238
|
-
const stateDir = (0, path_1.join)(claudeDir, 'state');
|
|
239
|
-
if (!(0, fs_1.existsSync)(stateDir)) {
|
|
240
|
-
(0, fs_1.mkdirSync)(stateDir, { recursive: true });
|
|
241
|
-
}
|
|
242
288
|
}
|
|
243
289
|
async function setupCursor(apiKey) {
|
|
244
290
|
// Cursor uses .cursorrules for system prompt
|
package/package.json
CHANGED
|
@@ -159,6 +159,12 @@ if [ -z "$RAW_SESSION_ID" ] || [ "$RAW_SESSION_ID" = "unknown" ] || [ "$RAW_SESS
|
|
|
159
159
|
if [ -f "$STATE_FILE" ] && [ -f "$JSON_PARSE_HELPER" ]; then
|
|
160
160
|
RAW_SESSION_ID=$(node "$JSON_PARSE_HELPER" "$STATE_FILE" '.session_id' 2>/dev/null || echo "unknown")
|
|
161
161
|
fi
|
|
162
|
+
|
|
163
|
+
# VSCode extension fallback: Extract session ID from transcript path
|
|
164
|
+
# Path format: ~/.claude/projects/<project>/<session-uuid>.jsonl
|
|
165
|
+
if [ "$RAW_SESSION_ID" = "unknown" ] && [ -n "$TRANSCRIPT_PATH" ] && [ -f "$TRANSCRIPT_PATH" ]; then
|
|
166
|
+
RAW_SESSION_ID=$(basename "$TRANSCRIPT_PATH" .jsonl)
|
|
167
|
+
fi
|
|
162
168
|
fi
|
|
163
169
|
|
|
164
170
|
# ═══════════════════════════════════════════════════════════════════════════
|