@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.
Files changed (98) hide show
  1. package/README.md +57 -0
  2. package/dist/agent/daemon.d.ts +27 -0
  3. package/dist/agent/daemon.js +254 -29
  4. package/dist/agent/health-check.d.ts +35 -0
  5. package/dist/agent/health-check.js +243 -0
  6. package/dist/agent/pty-runner.d.ts +1 -0
  7. package/dist/agent/pty-runner.js +6 -1
  8. package/dist/capture/eviction-client.d.ts +139 -0
  9. package/dist/capture/eviction-client.js +454 -0
  10. package/dist/capture/index.d.ts +2 -0
  11. package/dist/capture/index.js +2 -0
  12. package/dist/capture/jsonl-rewriter.d.ts +96 -0
  13. package/dist/capture/jsonl-rewriter.js +1369 -0
  14. package/dist/capture/transcript-repair.d.ts +51 -0
  15. package/dist/capture/transcript-repair.js +319 -0
  16. package/dist/commands/agent.d.ts +6 -0
  17. package/dist/commands/agent.js +244 -0
  18. package/dist/commands/dashboard.d.ts +25 -0
  19. package/dist/commands/dashboard.js +1175 -0
  20. package/dist/commands/doctor.js +23 -1
  21. package/dist/commands/run.d.ts +5 -0
  22. package/dist/commands/run.js +1605 -516
  23. package/dist/commands/setup-remote.js +146 -37
  24. package/dist/commands/swarm-dashboard.d.ts +20 -0
  25. package/dist/commands/swarm-dashboard.js +735 -0
  26. package/dist/commands/swarm-setup.d.ts +10 -0
  27. package/dist/commands/swarm-setup.js +956 -0
  28. package/dist/commands/swarm.d.ts +46 -0
  29. package/dist/commands/swarm.js +441 -0
  30. package/dist/commands/test-claude.d.ts +16 -0
  31. package/dist/commands/test-claude.js +156 -0
  32. package/dist/commands/usage/blocks.d.ts +8 -0
  33. package/dist/commands/usage/blocks.js +60 -0
  34. package/dist/commands/usage/daily.d.ts +9 -0
  35. package/dist/commands/usage/daily.js +96 -0
  36. package/dist/commands/usage/dashboard.d.ts +8 -0
  37. package/dist/commands/usage/dashboard.js +104 -0
  38. package/dist/commands/usage/formatters.d.ts +41 -0
  39. package/dist/commands/usage/formatters.js +147 -0
  40. package/dist/commands/usage/index.d.ts +13 -0
  41. package/dist/commands/usage/index.js +87 -0
  42. package/dist/commands/usage/monthly.d.ts +8 -0
  43. package/dist/commands/usage/monthly.js +66 -0
  44. package/dist/commands/usage/session.d.ts +11 -0
  45. package/dist/commands/usage/session.js +193 -0
  46. package/dist/commands/usage/weekly.d.ts +9 -0
  47. package/dist/commands/usage/weekly.js +61 -0
  48. package/dist/commands/usage.d.ts +7 -0
  49. package/dist/commands/usage.js +214 -0
  50. package/dist/cron/index.d.ts +7 -0
  51. package/dist/cron/index.js +13 -0
  52. package/dist/cron/promoter.d.ts +70 -0
  53. package/dist/cron/promoter.js +403 -0
  54. package/dist/deploy/instructions.d.ts +5 -2
  55. package/dist/deploy/instructions.js +11 -8
  56. package/dist/index.js +262 -5
  57. package/dist/lib/tmux-scrollbar.d.ts +14 -0
  58. package/dist/lib/tmux-scrollbar.js +296 -0
  59. package/dist/lib/usage-monitor.d.ts +47 -0
  60. package/dist/lib/usage-monitor.js +124 -0
  61. package/dist/lib/usage-parser.d.ts +162 -0
  62. package/dist/lib/usage-parser.js +583 -0
  63. package/dist/restore/RestoreOrchestrator.d.ts +4 -0
  64. package/dist/restore/RestoreOrchestrator.js +118 -30
  65. package/dist/utils/log-rotate.d.ts +18 -0
  66. package/dist/utils/log-rotate.js +74 -0
  67. package/dist/utils/platform.d.ts +2 -0
  68. package/dist/utils/platform.js +3 -1
  69. package/dist/utils/session-binding.d.ts +5 -0
  70. package/dist/utils/session-binding.js +46 -0
  71. package/dist/utils/state.js +4 -0
  72. package/dist/utils/verify-remote-terminal.d.ts +10 -0
  73. package/dist/utils/verify-remote-terminal.js +415 -0
  74. package/package.json +9 -2
  75. package/templates/CLAUDE.md +135 -23
  76. package/templates/ekkos-manifest.json +5 -5
  77. package/templates/hooks/lib/contract.sh +43 -31
  78. package/templates/hooks/lib/count-tokens.cjs +86 -0
  79. package/templates/hooks/lib/ekkos-reminders.sh +98 -0
  80. package/templates/hooks/lib/state.sh +53 -1
  81. package/templates/hooks/stop.sh +150 -388
  82. package/templates/hooks/user-prompt-submit.sh +353 -443
  83. package/templates/windsurf-hooks/README.md +212 -0
  84. package/templates/windsurf-hooks/hooks.json +9 -2
  85. package/templates/windsurf-hooks/install.sh +148 -0
  86. package/templates/windsurf-hooks/lib/contract.sh +2 -0
  87. package/templates/windsurf-hooks/post-cascade-response.sh +251 -0
  88. package/templates/windsurf-hooks/pre-user-prompt.sh +435 -0
  89. package/templates/windsurf-skills/ekkos-memory/SKILL.md +219 -0
  90. package/templates/agents/README.md +0 -182
  91. package/templates/agents/code-reviewer.md +0 -166
  92. package/templates/agents/debug-detective.md +0 -169
  93. package/templates/agents/ekkOS_Vercel.md +0 -99
  94. package/templates/agents/extension-manager.md +0 -229
  95. package/templates/agents/git-companion.md +0 -185
  96. package/templates/agents/github-test-agent.md +0 -321
  97. package/templates/agents/railway-manager.md +0 -215
  98. 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://api.ekkos.dev';
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
- return {
129
- ...streamResult,
130
- latency_ms: Date.now() - startTime,
131
- };
131
+ result = streamResult;
132
132
  }
133
- // Try Tier 0: Local cache
134
- const localResult = await this.restoreFromLocal(instanceId, sessionId, sessionName || '', lastN);
135
- if (localResult.success && localResult.data) {
136
- return {
137
- ...localResult,
138
- latency_ms: Date.now() - startTime,
139
- };
140
- }
141
- // Try Tier 1: Redis
142
- const redisResult = await this.restoreFromRedis(sessionName || sessionId, lastN, instanceId);
143
- if (redisResult.success && redisResult.data) {
144
- return {
145
- ...redisResult,
146
- latency_ms: Date.now() - startTime,
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
- // Try Tier 2: Supabase
150
- const supabaseResult = await this.restoreFromSupabase(sessionId, lastN, instanceId);
151
- if (supabaseResult.success && supabaseResult.data) {
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
- success: false,
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
+ }
@@ -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;
@@ -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,5 @@
1
+ /**
2
+ * Bind the real session name to the proxy
3
+ * This replaces the '_pending' placeholder for this user, enabling proper eviction
4
+ */
5
+ export declare function bindSession(realSession: string, projectPath: string, pendingSession?: string): Promise<boolean>;
@@ -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
+ }
@@ -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>;