@ekkos/cli 0.2.18 → 1.0.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.
- package/README.md +57 -0
- package/dist/agent/daemon.d.ts +27 -0
- package/dist/agent/daemon.js +254 -29
- package/dist/agent/health-check.d.ts +35 -0
- package/dist/agent/health-check.js +243 -0
- package/dist/agent/pty-runner.d.ts +1 -0
- package/dist/agent/pty-runner.js +6 -1
- package/dist/capture/eviction-client.d.ts +139 -0
- package/dist/capture/eviction-client.js +454 -0
- package/dist/capture/index.d.ts +2 -0
- package/dist/capture/index.js +2 -0
- package/dist/capture/jsonl-rewriter.d.ts +96 -0
- package/dist/capture/jsonl-rewriter.js +1369 -0
- package/dist/capture/transcript-repair.d.ts +51 -0
- package/dist/capture/transcript-repair.js +319 -0
- package/dist/commands/agent.d.ts +6 -0
- package/dist/commands/agent.js +244 -0
- package/dist/commands/dashboard.d.ts +25 -0
- package/dist/commands/dashboard.js +1175 -0
- package/dist/commands/doctor.js +23 -1
- package/dist/commands/run.d.ts +5 -0
- package/dist/commands/run.js +1605 -516
- package/dist/commands/setup-remote.js +146 -37
- package/dist/commands/swarm-dashboard.d.ts +20 -0
- package/dist/commands/swarm-dashboard.js +735 -0
- package/dist/commands/swarm-setup.d.ts +10 -0
- package/dist/commands/swarm-setup.js +956 -0
- package/dist/commands/swarm.d.ts +46 -0
- package/dist/commands/swarm.js +441 -0
- package/dist/commands/test-claude.d.ts +16 -0
- package/dist/commands/test-claude.js +156 -0
- package/dist/commands/usage/blocks.d.ts +8 -0
- package/dist/commands/usage/blocks.js +60 -0
- package/dist/commands/usage/daily.d.ts +9 -0
- package/dist/commands/usage/daily.js +96 -0
- package/dist/commands/usage/dashboard.d.ts +8 -0
- package/dist/commands/usage/dashboard.js +104 -0
- package/dist/commands/usage/formatters.d.ts +41 -0
- package/dist/commands/usage/formatters.js +147 -0
- package/dist/commands/usage/index.d.ts +13 -0
- package/dist/commands/usage/index.js +87 -0
- package/dist/commands/usage/monthly.d.ts +8 -0
- package/dist/commands/usage/monthly.js +66 -0
- package/dist/commands/usage/session.d.ts +11 -0
- package/dist/commands/usage/session.js +193 -0
- package/dist/commands/usage/weekly.d.ts +9 -0
- package/dist/commands/usage/weekly.js +61 -0
- package/dist/commands/usage.d.ts +7 -0
- package/dist/commands/usage.js +214 -0
- package/dist/cron/index.d.ts +7 -0
- package/dist/cron/index.js +13 -0
- package/dist/cron/promoter.d.ts +70 -0
- package/dist/cron/promoter.js +403 -0
- package/dist/deploy/instructions.d.ts +5 -2
- package/dist/deploy/instructions.js +11 -8
- package/dist/index.js +262 -5
- package/dist/lib/tmux-scrollbar.d.ts +14 -0
- package/dist/lib/tmux-scrollbar.js +296 -0
- package/dist/lib/usage-monitor.d.ts +47 -0
- package/dist/lib/usage-monitor.js +124 -0
- package/dist/lib/usage-parser.d.ts +162 -0
- package/dist/lib/usage-parser.js +583 -0
- package/dist/restore/RestoreOrchestrator.d.ts +4 -0
- package/dist/restore/RestoreOrchestrator.js +118 -30
- package/dist/utils/log-rotate.d.ts +18 -0
- package/dist/utils/log-rotate.js +74 -0
- package/dist/utils/platform.d.ts +2 -0
- package/dist/utils/platform.js +3 -1
- package/dist/utils/session-binding.d.ts +5 -0
- package/dist/utils/session-binding.js +46 -0
- package/dist/utils/state.js +4 -0
- package/dist/utils/verify-remote-terminal.d.ts +10 -0
- package/dist/utils/verify-remote-terminal.js +415 -0
- package/package.json +9 -2
- package/templates/CLAUDE.md +135 -23
- package/templates/ekkos-manifest.json +5 -5
- package/templates/hooks/lib/contract.sh +43 -31
- package/templates/hooks/lib/count-tokens.cjs +86 -0
- package/templates/hooks/lib/ekkos-reminders.sh +98 -0
- package/templates/hooks/lib/state.sh +53 -1
- package/templates/hooks/stop.sh +150 -388
- package/templates/hooks/user-prompt-submit.sh +353 -443
- package/templates/windsurf-hooks/README.md +212 -0
- package/templates/windsurf-hooks/hooks.json +9 -2
- package/templates/windsurf-hooks/install.sh +148 -0
- package/templates/windsurf-hooks/lib/contract.sh +2 -0
- package/templates/windsurf-hooks/post-cascade-response.sh +251 -0
- package/templates/windsurf-hooks/pre-user-prompt.sh +435 -0
- package/templates/windsurf-skills/ekkos-memory/SKILL.md +219 -0
- package/templates/agents/README.md +0 -182
- package/templates/agents/code-reviewer.md +0 -166
- package/templates/agents/debug-detective.md +0 -169
- package/templates/agents/ekkOS_Vercel.md +0 -99
- package/templates/agents/extension-manager.md +0 -229
- package/templates/agents/git-companion.md +0 -185
- package/templates/agents/github-test-agent.md +0 -321
- package/templates/agents/railway-manager.md +0 -215
- package/templates/windsurf-hooks/before-submit-prompt.sh +0 -238
|
@@ -58,8 +58,10 @@ const types_js_1 = require("../cache/types.js");
|
|
|
58
58
|
const stream_tailer_js_1 = require("../capture/stream-tailer.js");
|
|
59
59
|
const paths_js_1 = require("../utils/paths.js");
|
|
60
60
|
// API configuration
|
|
61
|
-
const MEMORY_API_URL = process.env.EKKOS_API_URL || 'https://
|
|
61
|
+
const MEMORY_API_URL = process.env.EKKOS_API_URL || 'https://mcp.ekkos.dev';
|
|
62
62
|
const CONFIG_PATH = path.join(os.homedir(), '.ekkos', 'config.json');
|
|
63
|
+
// Rehydration patterns
|
|
64
|
+
const STUB_REGEX = /\[ekkOS:page-out:r2:\/\/([^/]+)\/([^/]+)\/([^/]+)\/([^\]?]+)(?:\?range=(\d+)-(\d+))?\]/g;
|
|
63
65
|
/**
|
|
64
66
|
* Load auth token from config
|
|
65
67
|
*/
|
|
@@ -122,45 +124,131 @@ class RestoreOrchestrator {
|
|
|
122
124
|
latency_ms: Date.now() - startTime,
|
|
123
125
|
};
|
|
124
126
|
}
|
|
127
|
+
let result;
|
|
125
128
|
// Try Tier -1: Stream log (has mid-turn content, most recent data)
|
|
126
129
|
const streamResult = await this.restoreFromStreamLog(instanceId, sessionId, sessionName || '', lastN);
|
|
127
130
|
if (streamResult.success && streamResult.data) {
|
|
128
|
-
|
|
129
|
-
...streamResult,
|
|
130
|
-
latency_ms: Date.now() - startTime,
|
|
131
|
-
};
|
|
131
|
+
result = streamResult;
|
|
132
132
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
133
|
+
else {
|
|
134
|
+
// Try Tier 0: Local cache
|
|
135
|
+
const localResult = await this.restoreFromLocal(instanceId, sessionId, sessionName || '', lastN);
|
|
136
|
+
if (localResult.success && localResult.data) {
|
|
137
|
+
result = localResult;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
// Try Tier 1: Redis
|
|
141
|
+
const redisResult = await this.restoreFromRedis(sessionName || sessionId, lastN, instanceId);
|
|
142
|
+
if (redisResult.success && redisResult.data) {
|
|
143
|
+
result = redisResult;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
// Try Tier 2: Supabase
|
|
147
|
+
const supabaseResult = await this.restoreFromSupabase(sessionId, lastN, instanceId);
|
|
148
|
+
if (supabaseResult.success && supabaseResult.data) {
|
|
149
|
+
result = supabaseResult;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// All tiers failed
|
|
153
|
+
return {
|
|
154
|
+
success: false,
|
|
155
|
+
error: `All restore tiers failed. Local: ${localResult.error}, Redis: ${redisResult.error}, Supabase: ${supabaseResult.error}`,
|
|
156
|
+
latency_ms: Date.now() - startTime,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
148
161
|
}
|
|
149
|
-
//
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
return {
|
|
153
|
-
...supabaseResult,
|
|
154
|
-
latency_ms: Date.now() - startTime,
|
|
155
|
-
};
|
|
162
|
+
// Rehydrate stubs if any found in restored payload
|
|
163
|
+
if (result.success && result.data) {
|
|
164
|
+
await this.rehydratePayload(result.data);
|
|
156
165
|
}
|
|
157
|
-
// All tiers failed
|
|
158
166
|
return {
|
|
159
|
-
|
|
160
|
-
error: `All restore tiers failed. Local: ${localResult.error}, Redis: ${redisResult.error}, Supabase: ${supabaseResult.error}`,
|
|
167
|
+
...result,
|
|
161
168
|
latency_ms: Date.now() - startTime,
|
|
162
169
|
};
|
|
163
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Scan payload for [ekkOS:page-out:...] stubs and rehydrate from Proxy
|
|
173
|
+
*/
|
|
174
|
+
async rehydratePayload(payload) {
|
|
175
|
+
const stubs = new Set();
|
|
176
|
+
// Scan all restored turns (both user queries and assistant responses)
|
|
177
|
+
// Stubs are injected as user messages, so check user_query too
|
|
178
|
+
for (const turn of payload.restored_turns) {
|
|
179
|
+
for (const text of [turn.user_query, turn.assistant_response]) {
|
|
180
|
+
if (!text)
|
|
181
|
+
continue;
|
|
182
|
+
STUB_REGEX.lastIndex = 0;
|
|
183
|
+
const matches = text.match(STUB_REGEX);
|
|
184
|
+
if (matches) {
|
|
185
|
+
for (const match of matches)
|
|
186
|
+
stubs.add(match);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Also scan latest (both user and assistant)
|
|
191
|
+
for (const text of [payload.latest.user_query, payload.latest.assistant_response]) {
|
|
192
|
+
if (!text)
|
|
193
|
+
continue;
|
|
194
|
+
STUB_REGEX.lastIndex = 0;
|
|
195
|
+
const matches = text.match(STUB_REGEX);
|
|
196
|
+
if (matches) {
|
|
197
|
+
for (const match of matches)
|
|
198
|
+
stubs.add(match);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (stubs.size === 0)
|
|
202
|
+
return;
|
|
203
|
+
console.log(`[Restore] Detected ${stubs.size} stubs, rehydrating...`);
|
|
204
|
+
try {
|
|
205
|
+
const url = `${MEMORY_API_URL}/api/v1/context/rehydrate`;
|
|
206
|
+
const response = await fetch(url, {
|
|
207
|
+
method: 'POST',
|
|
208
|
+
headers: {
|
|
209
|
+
'Authorization': `Bearer ${this.authToken}`,
|
|
210
|
+
'Content-Type': 'application/json',
|
|
211
|
+
},
|
|
212
|
+
body: JSON.stringify({ stubs: Array.from(stubs) }),
|
|
213
|
+
signal: AbortSignal.timeout(10000),
|
|
214
|
+
});
|
|
215
|
+
if (!response.ok) {
|
|
216
|
+
console.warn(`[Restore] Rehydration API failed: ${response.status}`);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const { rehydrated } = await response.json();
|
|
220
|
+
if (!rehydrated || !Array.isArray(rehydrated))
|
|
221
|
+
return;
|
|
222
|
+
// Create mapping of stub -> content
|
|
223
|
+
const stubMap = new Map();
|
|
224
|
+
for (const entry of rehydrated) {
|
|
225
|
+
const content = entry.messages.map((m) => {
|
|
226
|
+
const role = m.role === 'user' ? 'U' : 'A';
|
|
227
|
+
const text = typeof m.content === 'string'
|
|
228
|
+
? m.content
|
|
229
|
+
: Array.isArray(m.content)
|
|
230
|
+
? m.content.map((b) => b.text || '').join('\n')
|
|
231
|
+
: '';
|
|
232
|
+
return `${role}: ${text}`;
|
|
233
|
+
}).join('\n\n');
|
|
234
|
+
stubMap.set(entry.stub, content);
|
|
235
|
+
}
|
|
236
|
+
// Replace stubs in turns
|
|
237
|
+
for (const turn of payload.restored_turns) {
|
|
238
|
+
for (const [stub, content] of stubMap.entries()) {
|
|
239
|
+
turn.assistant_response = turn.assistant_response.replace(stub, `[REHYDRATED CONTENT]\n${content}`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
// Replace stubs in latest
|
|
243
|
+
for (const [stub, content] of stubMap.entries()) {
|
|
244
|
+
payload.latest.assistant_response = payload.latest.assistant_response.replace(stub, `[REHYDRATED CONTENT]\n${content}`);
|
|
245
|
+
}
|
|
246
|
+
console.log(`[Restore] Successfully rehydrated ${stubMap.size} stubs`);
|
|
247
|
+
}
|
|
248
|
+
catch (err) {
|
|
249
|
+
console.warn(`[Restore] Rehydration error: ${err instanceof Error ? err.message : String(err)}`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
164
252
|
/**
|
|
165
253
|
* Tier -1: Restore from stream log (has mid-turn content)
|
|
166
254
|
* This is checked FIRST because stream logs have the most recent data,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rotate a log file if it exceeds the maximum size.
|
|
3
|
+
* Shifts existing backups up (e.g., .1 → .2, .2 → .3) and deletes the oldest if it exceeds maxBackups.
|
|
4
|
+
*
|
|
5
|
+
* @param logPath - Path to the log file
|
|
6
|
+
* @param maxBytes - Maximum file size in bytes before rotation (default: 5MB)
|
|
7
|
+
* @param maxBackups - Maximum number of backup files to keep (default: 3)
|
|
8
|
+
*/
|
|
9
|
+
export declare function rotateLogIfNeeded(logPath: string, maxBytes?: number, maxBackups?: number): void;
|
|
10
|
+
/**
|
|
11
|
+
* Append a message to a log file, rotating it first if needed.
|
|
12
|
+
* Creates the directory if it doesn't exist.
|
|
13
|
+
*
|
|
14
|
+
* @param logPath - Path to the log file
|
|
15
|
+
* @param message - Message to append
|
|
16
|
+
* @param maxBytes - Maximum file size in bytes before rotation (default: 5MB)
|
|
17
|
+
*/
|
|
18
|
+
export declare function appendLog(logPath: string, message: string, maxBytes?: number): void;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.rotateLogIfNeeded = rotateLogIfNeeded;
|
|
7
|
+
exports.appendLog = appendLog;
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
/**
|
|
11
|
+
* Rotate a log file if it exceeds the maximum size.
|
|
12
|
+
* Shifts existing backups up (e.g., .1 → .2, .2 → .3) and deletes the oldest if it exceeds maxBackups.
|
|
13
|
+
*
|
|
14
|
+
* @param logPath - Path to the log file
|
|
15
|
+
* @param maxBytes - Maximum file size in bytes before rotation (default: 5MB)
|
|
16
|
+
* @param maxBackups - Maximum number of backup files to keep (default: 3)
|
|
17
|
+
*/
|
|
18
|
+
function rotateLogIfNeeded(logPath, maxBytes = 5 * 1024 * 1024, maxBackups = 3) {
|
|
19
|
+
try {
|
|
20
|
+
// Check if log file exists and get its size
|
|
21
|
+
if (!fs_1.default.existsSync(logPath)) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const stats = fs_1.default.statSync(logPath);
|
|
25
|
+
if (stats.size < maxBytes) {
|
|
26
|
+
return; // No rotation needed
|
|
27
|
+
}
|
|
28
|
+
// Delete the oldest backup if it would exceed maxBackups
|
|
29
|
+
const oldestBackup = `${logPath}.${maxBackups}`;
|
|
30
|
+
if (fs_1.default.existsSync(oldestBackup)) {
|
|
31
|
+
fs_1.default.unlinkSync(oldestBackup);
|
|
32
|
+
}
|
|
33
|
+
// Shift existing backups up (e.g., .2 → .3, .1 → .2)
|
|
34
|
+
for (let i = maxBackups - 1; i >= 1; i--) {
|
|
35
|
+
const currentBackup = `${logPath}.${i}`;
|
|
36
|
+
const nextBackup = `${logPath}.${i + 1}`;
|
|
37
|
+
if (fs_1.default.existsSync(currentBackup)) {
|
|
38
|
+
fs_1.default.renameSync(currentBackup, nextBackup);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Rotate the current log to .1
|
|
42
|
+
fs_1.default.renameSync(logPath, `${logPath}.1`);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
// Silently fail - logging utilities should never crash the caller
|
|
46
|
+
// In a production scenario, you might want to log this to stderr or a separate error log
|
|
47
|
+
// console.error('[log-rotate] Failed to rotate log:', error);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Append a message to a log file, rotating it first if needed.
|
|
52
|
+
* Creates the directory if it doesn't exist.
|
|
53
|
+
*
|
|
54
|
+
* @param logPath - Path to the log file
|
|
55
|
+
* @param message - Message to append
|
|
56
|
+
* @param maxBytes - Maximum file size in bytes before rotation (default: 5MB)
|
|
57
|
+
*/
|
|
58
|
+
function appendLog(logPath, message, maxBytes) {
|
|
59
|
+
try {
|
|
60
|
+
// Create directory if it doesn't exist
|
|
61
|
+
const dir = path_1.default.dirname(logPath);
|
|
62
|
+
if (!fs_1.default.existsSync(dir)) {
|
|
63
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
64
|
+
}
|
|
65
|
+
// Rotate if needed
|
|
66
|
+
rotateLogIfNeeded(logPath, maxBytes);
|
|
67
|
+
// Append message
|
|
68
|
+
fs_1.default.appendFileSync(logPath, message + '\n', 'utf8');
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
// Silently fail - logging utilities should never crash the caller
|
|
72
|
+
// console.error('[log-rotate] Failed to append log:', error);
|
|
73
|
+
}
|
|
74
|
+
}
|
package/dist/utils/platform.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ export declare const CLAUDE_AGENTS_DIR: string;
|
|
|
15
15
|
export declare const CLAUDE_PLUGINS_DIR: string;
|
|
16
16
|
export declare const CLAUDE_STATE_DIR: string;
|
|
17
17
|
export declare const CLAUDE_MD: string;
|
|
18
|
+
export declare const CLAUDE_RULES_DIR: string;
|
|
19
|
+
export declare const CLAUDE_EKKOS_RULES: string;
|
|
18
20
|
export declare const CURSOR_DIR: string;
|
|
19
21
|
export declare const CURSOR_MCP: string;
|
|
20
22
|
export declare const WINDSURF_DIR: string;
|
package/dist/utils/platform.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.WINDSURF_MCP = exports.WINDSURF_DIR = exports.CURSOR_MCP = exports.CURSOR_DIR = exports.CLAUDE_MD = exports.CLAUDE_STATE_DIR = exports.CLAUDE_PLUGINS_DIR = exports.CLAUDE_AGENTS_DIR = exports.CLAUDE_SKILLS_DIR = exports.CLAUDE_HOOKS_DIR = exports.CLAUDE_SETTINGS = exports.CLAUDE_CONFIG = exports.CLAUDE_DIR = exports.EKKOS_CONFIG = exports.EKKOS_DIR = exports.HOME_DIR = exports.MCP_API_URL = exports.PLATFORM_URL = exports.isLinux = exports.isMac = exports.isWindows = void 0;
|
|
3
|
+
exports.WINDSURF_MCP = exports.WINDSURF_DIR = exports.CURSOR_MCP = exports.CURSOR_DIR = exports.CLAUDE_EKKOS_RULES = exports.CLAUDE_RULES_DIR = exports.CLAUDE_MD = exports.CLAUDE_STATE_DIR = exports.CLAUDE_PLUGINS_DIR = exports.CLAUDE_AGENTS_DIR = exports.CLAUDE_SKILLS_DIR = exports.CLAUDE_HOOKS_DIR = exports.CLAUDE_SETTINGS = exports.CLAUDE_CONFIG = exports.CLAUDE_DIR = exports.EKKOS_CONFIG = exports.EKKOS_DIR = exports.HOME_DIR = exports.MCP_API_URL = exports.PLATFORM_URL = exports.isLinux = exports.isMac = exports.isWindows = void 0;
|
|
4
4
|
exports.detectInstalledIDEs = detectInstalledIDEs;
|
|
5
5
|
exports.detectCurrentIDE = detectCurrentIDE;
|
|
6
6
|
const os_1 = require("os");
|
|
@@ -24,6 +24,8 @@ exports.CLAUDE_AGENTS_DIR = (0, path_1.join)(exports.CLAUDE_DIR, 'agents');
|
|
|
24
24
|
exports.CLAUDE_PLUGINS_DIR = (0, path_1.join)(exports.CLAUDE_DIR, 'plugins', 'ekkos');
|
|
25
25
|
exports.CLAUDE_STATE_DIR = (0, path_1.join)(exports.CLAUDE_DIR, 'state');
|
|
26
26
|
exports.CLAUDE_MD = (0, path_1.join)(exports.CLAUDE_DIR, 'CLAUDE.md');
|
|
27
|
+
exports.CLAUDE_RULES_DIR = (0, path_1.join)(exports.CLAUDE_DIR, 'rules');
|
|
28
|
+
exports.CLAUDE_EKKOS_RULES = (0, path_1.join)(exports.CLAUDE_RULES_DIR, 'ekkos.md');
|
|
27
29
|
exports.CURSOR_DIR = (0, path_1.join)(exports.HOME_DIR, '.cursor');
|
|
28
30
|
exports.CURSOR_MCP = (0, path_1.join)(exports.CURSOR_DIR, 'mcp.json');
|
|
29
31
|
exports.WINDSURF_DIR = (0, path_1.join)(exports.HOME_DIR, '.codeium', 'windsurf');
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.bindSession = bindSession;
|
|
4
|
+
const state_1 = require("./state");
|
|
5
|
+
const MEMORY_API_URL = process.env.EKKOS_PROXY_URL || 'https://proxy.ekkos.dev';
|
|
6
|
+
/**
|
|
7
|
+
* Bind the real session name to the proxy
|
|
8
|
+
* This replaces the '_pending' placeholder for this user, enabling proper eviction
|
|
9
|
+
*/
|
|
10
|
+
async function bindSession(realSession, projectPath, pendingSession) {
|
|
11
|
+
try {
|
|
12
|
+
// Get userId same way as run.ts
|
|
13
|
+
const config = (0, state_1.getConfig)();
|
|
14
|
+
let userId = config?.userId;
|
|
15
|
+
if (!userId || userId === 'anonymous') {
|
|
16
|
+
const token = (0, state_1.getAuthToken)();
|
|
17
|
+
if (token?.startsWith('ekk_')) {
|
|
18
|
+
const parts = token.split('_');
|
|
19
|
+
if (parts.length >= 2) {
|
|
20
|
+
userId = parts[1];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (!userId || userId === 'anonymous')
|
|
25
|
+
return false;
|
|
26
|
+
// Use global fetch (Node 18+)
|
|
27
|
+
const response = await fetch(`${MEMORY_API_URL}/proxy/session/bind`, {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
signal: AbortSignal.timeout(2500),
|
|
30
|
+
headers: {
|
|
31
|
+
'Content-Type': 'application/json'
|
|
32
|
+
},
|
|
33
|
+
body: JSON.stringify({
|
|
34
|
+
userId,
|
|
35
|
+
realSession,
|
|
36
|
+
projectPath,
|
|
37
|
+
pendingSession: pendingSession || null,
|
|
38
|
+
})
|
|
39
|
+
});
|
|
40
|
+
return response.ok;
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
// Fail silently - don't crash CLI
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
package/dist/utils/state.js
CHANGED
|
@@ -341,6 +341,10 @@ function getActiveSessionByName(sessionName) {
|
|
|
341
341
|
* Check if a process is still alive
|
|
342
342
|
*/
|
|
343
343
|
function isProcessAlive(pid) {
|
|
344
|
+
// pid <= 1 (including 0 placeholders from hooks) are not valid user processes.
|
|
345
|
+
if (!Number.isInteger(pid) || pid <= 1) {
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
344
348
|
try {
|
|
345
349
|
// Sending signal 0 doesn't kill the process, just checks if it exists
|
|
346
350
|
process.kill(pid, 0);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remote Terminal Verification Script
|
|
3
|
+
*
|
|
4
|
+
* Systematically verifies that all remote terminal components are properly configured
|
|
5
|
+
* and working correctly. Run this after setup-remote to validate the installation.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Run all verification tests
|
|
9
|
+
*/
|
|
10
|
+
export declare function verifyRemoteTerminal(): Promise<void>;
|