@ekkos/cli 1.3.1 → 1.3.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 (131) hide show
  1. package/dist/capture/jsonl-rewriter.d.ts +1 -1
  2. package/dist/capture/jsonl-rewriter.js +3 -3
  3. package/dist/capture/transcript-repair.d.ts +2 -2
  4. package/dist/capture/transcript-repair.js +2 -2
  5. package/dist/commands/claw.d.ts +13 -0
  6. package/dist/commands/claw.js +253 -0
  7. package/dist/commands/dashboard.js +742 -118
  8. package/dist/commands/doctor.d.ts +3 -3
  9. package/dist/commands/doctor.js +6 -79
  10. package/dist/commands/gemini.d.ts +19 -0
  11. package/dist/commands/gemini.js +193 -0
  12. package/dist/commands/init.d.ts +1 -0
  13. package/dist/commands/init.js +56 -41
  14. package/dist/commands/run.d.ts +0 -1
  15. package/dist/commands/run.js +288 -263
  16. package/dist/commands/scan.d.ts +21 -0
  17. package/dist/commands/scan.js +386 -0
  18. package/dist/commands/status.d.ts +4 -1
  19. package/dist/commands/status.js +165 -27
  20. package/dist/commands/swarm-dashboard.js +156 -28
  21. package/dist/commands/swarm.d.ts +1 -1
  22. package/dist/commands/swarm.js +1 -1
  23. package/dist/commands/test-claude.d.ts +2 -2
  24. package/dist/commands/test-claude.js +3 -3
  25. package/dist/deploy/index.d.ts +0 -2
  26. package/dist/deploy/index.js +0 -2
  27. package/dist/deploy/settings.d.ts +6 -5
  28. package/dist/deploy/settings.js +64 -16
  29. package/dist/deploy/skills.js +1 -2
  30. package/dist/index.js +86 -96
  31. package/dist/lib/usage-parser.d.ts +1 -1
  32. package/dist/lib/usage-parser.js +9 -6
  33. package/dist/local/index.d.ts +14 -0
  34. package/dist/local/index.js +28 -0
  35. package/dist/local/local-embeddings.d.ts +49 -0
  36. package/dist/local/local-embeddings.js +232 -0
  37. package/dist/local/offline-fallback.d.ts +44 -0
  38. package/dist/local/offline-fallback.js +159 -0
  39. package/dist/local/sqlite-store.d.ts +126 -0
  40. package/dist/local/sqlite-store.js +393 -0
  41. package/dist/local/sync-engine.d.ts +42 -0
  42. package/dist/local/sync-engine.js +223 -0
  43. package/dist/utils/platform.d.ts +5 -1
  44. package/dist/utils/platform.js +24 -4
  45. package/dist/utils/proxy-url.d.ts +21 -0
  46. package/dist/utils/proxy-url.js +34 -0
  47. package/dist/utils/state.d.ts +1 -1
  48. package/dist/utils/state.js +11 -3
  49. package/dist/utils/templates.js +1 -1
  50. package/package.json +11 -4
  51. package/templates/CLAUDE.md +49 -107
  52. package/dist/agent/daemon.d.ts +0 -130
  53. package/dist/agent/daemon.js +0 -606
  54. package/dist/agent/health-check.d.ts +0 -35
  55. package/dist/agent/health-check.js +0 -243
  56. package/dist/agent/pty-runner.d.ts +0 -53
  57. package/dist/agent/pty-runner.js +0 -190
  58. package/dist/commands/agent.d.ts +0 -50
  59. package/dist/commands/agent.js +0 -544
  60. package/dist/commands/setup-remote.d.ts +0 -20
  61. package/dist/commands/setup-remote.js +0 -582
  62. package/dist/utils/verify-remote-terminal.d.ts +0 -10
  63. package/dist/utils/verify-remote-terminal.js +0 -415
  64. package/templates/README.md +0 -378
  65. package/templates/claude-plugins/PHASE2_COMPLETION.md +0 -346
  66. package/templates/claude-plugins/PLUGIN_PROPOSALS.md +0 -1776
  67. package/templates/claude-plugins/README.md +0 -587
  68. package/templates/claude-plugins/agents/code-reviewer.json +0 -14
  69. package/templates/claude-plugins/agents/debug-detective.json +0 -15
  70. package/templates/claude-plugins/agents/git-companion.json +0 -14
  71. package/templates/claude-plugins/blog-manager/.claude-plugin/plugin.json +0 -8
  72. package/templates/claude-plugins/blog-manager/commands/blog.md +0 -691
  73. package/templates/claude-plugins/golden-loop-monitor/.claude-plugin/plugin.json +0 -8
  74. package/templates/claude-plugins/golden-loop-monitor/commands/loop-status.md +0 -434
  75. package/templates/claude-plugins/learning-tracker/.claude-plugin/plugin.json +0 -8
  76. package/templates/claude-plugins/learning-tracker/commands/my-patterns.md +0 -282
  77. package/templates/claude-plugins/memory-lens/.claude-plugin/plugin.json +0 -8
  78. package/templates/claude-plugins/memory-lens/commands/memory-search.md +0 -181
  79. package/templates/claude-plugins/pattern-coach/.claude-plugin/plugin.json +0 -8
  80. package/templates/claude-plugins/pattern-coach/commands/forge.md +0 -365
  81. package/templates/claude-plugins/project-schema-validator/.claude-plugin/plugin.json +0 -8
  82. package/templates/claude-plugins/project-schema-validator/commands/validate-schema.md +0 -582
  83. package/templates/claude-plugins-admin/AGENT_TEAM_PROPOSALS.md +0 -819
  84. package/templates/claude-plugins-admin/README.md +0 -446
  85. package/templates/claude-plugins-admin/autonomous-admin-agent/.claude-plugin/plugin.json +0 -8
  86. package/templates/claude-plugins-admin/autonomous-admin-agent/commands/agent.md +0 -595
  87. package/templates/claude-plugins-admin/backend-agent/.claude-plugin/plugin.json +0 -8
  88. package/templates/claude-plugins-admin/backend-agent/commands/backend.md +0 -798
  89. package/templates/claude-plugins-admin/deploy-guardian/.claude-plugin/plugin.json +0 -8
  90. package/templates/claude-plugins-admin/deploy-guardian/commands/deploy.md +0 -554
  91. package/templates/claude-plugins-admin/frontend-agent/.claude-plugin/plugin.json +0 -8
  92. package/templates/claude-plugins-admin/frontend-agent/commands/frontend.md +0 -881
  93. package/templates/claude-plugins-admin/mcp-server-manager/.claude-plugin/plugin.json +0 -8
  94. package/templates/claude-plugins-admin/mcp-server-manager/commands/mcp.md +0 -85
  95. package/templates/claude-plugins-admin/memory-system-monitor/.claude-plugin/plugin.json +0 -8
  96. package/templates/claude-plugins-admin/memory-system-monitor/commands/memory-health.md +0 -569
  97. package/templates/claude-plugins-admin/qa-agent/.claude-plugin/plugin.json +0 -8
  98. package/templates/claude-plugins-admin/qa-agent/commands/qa.md +0 -863
  99. package/templates/claude-plugins-admin/tech-lead-agent/.claude-plugin/plugin.json +0 -8
  100. package/templates/claude-plugins-admin/tech-lead-agent/commands/lead.md +0 -732
  101. package/templates/commands/continue.md +0 -47
  102. package/templates/cursor-rules/ekkos-memory.md +0 -127
  103. package/templates/ekkos-manifest.json +0 -223
  104. package/templates/helpers/json-parse.cjs +0 -101
  105. package/templates/hooks-node/lib/state.js +0 -187
  106. package/templates/hooks-node/stop.js +0 -416
  107. package/templates/hooks-node/user-prompt-submit.js +0 -337
  108. package/templates/plan-template.md +0 -306
  109. package/templates/rules/00-hooks-contract.mdc +0 -89
  110. package/templates/rules/30-ekkos-core.mdc +0 -188
  111. package/templates/rules/31-ekkos-messages.mdc +0 -78
  112. package/templates/shared/hooks-enabled.json +0 -22
  113. package/templates/shared/session-words.json +0 -45
  114. package/templates/skills/ekkOS_Deep_Recall/Skill.md +0 -282
  115. package/templates/skills/ekkOS_Learn/Skill.md +0 -265
  116. package/templates/skills/ekkOS_Memory_First/Skill.md +0 -206
  117. package/templates/skills/ekkOS_Plan_Assist/Skill.md +0 -302
  118. package/templates/skills/ekkOS_Preferences/Skill.md +0 -247
  119. package/templates/skills/ekkOS_Reflect/Skill.md +0 -257
  120. package/templates/skills/ekkOS_Safety/Skill.md +0 -265
  121. package/templates/skills/ekkOS_Schema/Skill.md +0 -251
  122. package/templates/skills/ekkOS_Summary/Skill.md +0 -257
  123. package/templates/spec-template.md +0 -159
  124. package/templates/windsurf-rules/ekkos-memory.md +0 -127
  125. package/templates/windsurf-skills/README.md +0 -58
  126. package/templates/windsurf-skills/ekkos-continue/SKILL.md +0 -81
  127. package/templates/windsurf-skills/ekkos-golden-loop/SKILL.md +0 -225
  128. package/templates/windsurf-skills/ekkos-insights/SKILL.md +0 -138
  129. package/templates/windsurf-skills/ekkos-recall/SKILL.md +0 -96
  130. package/templates/windsurf-skills/ekkos-safety/SKILL.md +0 -89
  131. package/templates/windsurf-skills/ekkos-vault/SKILL.md +0 -86
@@ -1,582 +0,0 @@
1
- "use strict";
2
- /**
3
- * ekkos setup-remote - One-command setup for remote terminal access
4
- *
5
- * This command does everything automatically:
6
- * 1. Checks if user is logged in (prompts login if not)
7
- * 2. Generates unique device ID and fingerprint
8
- * 3. Opens browser for device pairing approval
9
- * 4. Installs background agent as system service
10
- * 5. Starts agent immediately
11
- * 6. Verifies connection to cloud relay
12
- */
13
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
- if (k2 === undefined) k2 = k;
15
- var desc = Object.getOwnPropertyDescriptor(m, k);
16
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
- desc = { enumerable: true, get: function() { return m[k]; } };
18
- }
19
- Object.defineProperty(o, k2, desc);
20
- }) : (function(o, m, k, k2) {
21
- if (k2 === undefined) k2 = k;
22
- o[k2] = m[k];
23
- }));
24
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
- Object.defineProperty(o, "default", { enumerable: true, value: v });
26
- }) : function(o, v) {
27
- o["default"] = v;
28
- });
29
- var __importStar = (this && this.__importStar) || (function () {
30
- var ownKeys = function(o) {
31
- ownKeys = Object.getOwnPropertyNames || function (o) {
32
- var ar = [];
33
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
- return ar;
35
- };
36
- return ownKeys(o);
37
- };
38
- return function (mod) {
39
- if (mod && mod.__esModule) return mod;
40
- var result = {};
41
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
- __setModuleDefault(result, mod);
43
- return result;
44
- };
45
- })();
46
- var __importDefault = (this && this.__importDefault) || function (mod) {
47
- return (mod && mod.__esModule) ? mod : { "default": mod };
48
- };
49
- Object.defineProperty(exports, "__esModule", { value: true });
50
- exports.setupRemote = setupRemote;
51
- const chalk_1 = __importDefault(require("chalk"));
52
- const os = __importStar(require("os"));
53
- const fs = __importStar(require("fs"));
54
- const path = __importStar(require("path"));
55
- const crypto = __importStar(require("crypto"));
56
- const child_process_1 = require("child_process");
57
- const open_1 = __importDefault(require("open"));
58
- const state_1 = require("../utils/state");
59
- const init_1 = require("./init");
60
- // Get version from package.json (CommonJS compatible)
61
- const pkgPath = path.resolve(__dirname, '../../package.json');
62
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
63
- const PLATFORM_URL = process.env.PLATFORM_URL || 'https://platform.ekkos.dev';
64
- const RELAY_API_URL = process.env.RELAY_URL || 'https://ekkos-relay-production.up.railway.app';
65
- const POLLING_INTERVAL = 2000; // 2 seconds
66
- const POLLING_TIMEOUT = 600000; // 10 minutes
67
- /**
68
- * Get or create device info
69
- */
70
- function getOrCreateDeviceInfo() {
71
- const deviceFilePath = path.join(state_1.EKKOS_DIR, 'device.json');
72
- // Check if device already registered
73
- if (fs.existsSync(deviceFilePath)) {
74
- const existing = JSON.parse(fs.readFileSync(deviceFilePath, 'utf-8'));
75
- if (existing.deviceId) {
76
- return existing;
77
- }
78
- }
79
- // Generate new device ID
80
- const deviceId = crypto.randomUUID();
81
- // Get device name from hostname or system info
82
- let deviceName = os.hostname();
83
- if (os.platform() === 'darwin') {
84
- try {
85
- const computerName = (0, child_process_1.execSync)('scutil --get ComputerName', { encoding: 'utf-8' }).trim();
86
- if (computerName)
87
- deviceName = computerName;
88
- }
89
- catch {
90
- // Fall back to hostname
91
- }
92
- }
93
- const deviceInfo = {
94
- deviceId,
95
- deviceName,
96
- hostname: os.hostname(),
97
- platform: os.platform(),
98
- arch: os.arch(),
99
- nodeVersion: process.version,
100
- cliVersion: pkg.version,
101
- };
102
- // Save device info
103
- if (!fs.existsSync(state_1.EKKOS_DIR)) {
104
- fs.mkdirSync(state_1.EKKOS_DIR, { recursive: true });
105
- }
106
- fs.writeFileSync(deviceFilePath, JSON.stringify(deviceInfo, null, 2));
107
- return deviceInfo;
108
- }
109
- /**
110
- * Request device pairing code from server
111
- */
112
- async function requestPairingCode(deviceInfo, authToken) {
113
- const response = await fetch(`${RELAY_API_URL}/api/v1/relay/pair`, {
114
- method: 'POST',
115
- headers: {
116
- 'Authorization': `Bearer ${authToken}`,
117
- 'Content-Type': 'application/json',
118
- },
119
- body: JSON.stringify({
120
- deviceId: deviceInfo.deviceId,
121
- deviceName: deviceInfo.deviceName,
122
- hostname: deviceInfo.hostname,
123
- platform: deviceInfo.platform,
124
- arch: deviceInfo.arch,
125
- fingerprint: deviceInfo,
126
- }),
127
- });
128
- if (!response.ok) {
129
- const errorData = await response.json().catch(() => ({ error: 'Unknown error' }));
130
- const errorMessage = typeof errorData === 'string'
131
- ? errorData
132
- : errorData.error || errorData.message || JSON.stringify(errorData);
133
- throw new Error(errorMessage || `Failed to request pairing code: ${response.status}`);
134
- }
135
- return response.json();
136
- }
137
- /**
138
- * Poll for pairing approval
139
- */
140
- async function pollForApproval(deviceCode, authToken) {
141
- const startTime = Date.now();
142
- while (Date.now() - startTime < POLLING_TIMEOUT) {
143
- const response = await fetch(`${RELAY_API_URL}/api/v1/relay/pair/${deviceCode}`, {
144
- headers: {
145
- 'Authorization': `Bearer ${authToken}`,
146
- },
147
- });
148
- if (response.status === 200) {
149
- const data = await response.json();
150
- if (data.status === 'approved') {
151
- return { approved: true, deviceToken: data.deviceToken };
152
- }
153
- }
154
- else if (response.status === 403) {
155
- // Denied
156
- return { approved: false };
157
- }
158
- else if (response.status === 410) {
159
- // Expired
160
- throw new Error('Pairing code expired');
161
- }
162
- // Wait before next poll
163
- await new Promise(resolve => setTimeout(resolve, POLLING_INTERVAL));
164
- process.stdout.write('.');
165
- }
166
- throw new Error('Pairing timeout');
167
- }
168
- /**
169
- * Install agent as system service
170
- */
171
- async function installService(verbose) {
172
- const platform = os.platform();
173
- if (platform === 'darwin') {
174
- await installMacOSService(verbose);
175
- }
176
- else if (platform === 'win32') {
177
- await installWindowsService(verbose);
178
- }
179
- else if (platform === 'linux') {
180
- await installLinuxService(verbose);
181
- }
182
- else {
183
- throw new Error(`Unsupported platform: ${platform}`);
184
- }
185
- }
186
- /**
187
- * Install macOS launchd service
188
- */
189
- async function installMacOSService(verbose) {
190
- const plistName = 'dev.ekkos.agent';
191
- const plistPath = path.join(os.homedir(), 'Library', 'LaunchAgents', `${plistName}.plist`);
192
- // Find node path - use execPath of current process
193
- const nodePath = process.execPath;
194
- if (verbose) {
195
- console.log(chalk_1.default.gray(` Node path: ${nodePath}`));
196
- }
197
- // Find ekkos CLI path
198
- let ekkosPath;
199
- let useNpx = false;
200
- try {
201
- ekkosPath = (0, child_process_1.execSync)('which ekkos', { encoding: 'utf-8' }).trim();
202
- if (!ekkosPath)
203
- throw new Error('Empty path');
204
- }
205
- catch {
206
- // Fall back to npx
207
- ekkosPath = 'npx';
208
- useNpx = true;
209
- }
210
- if (verbose) {
211
- console.log(chalk_1.default.gray(` ekkOS path: ${ekkosPath}${useNpx ? ' (via npx)' : ''}`));
212
- }
213
- // Build program arguments
214
- const programArgs = [nodePath];
215
- if (useNpx) {
216
- programArgs.push(ekkosPath);
217
- programArgs.push('@ekkos/cli');
218
- }
219
- else {
220
- programArgs.push(ekkosPath);
221
- }
222
- programArgs.push('agent');
223
- programArgs.push('daemon');
224
- // Build plist XML programmatically to avoid string template issues
225
- const plistContent = buildPlist(plistName, programArgs, nodePath);
226
- // Ensure directory exists
227
- const launchAgentsDir = path.dirname(plistPath);
228
- if (!fs.existsSync(launchAgentsDir)) {
229
- fs.mkdirSync(launchAgentsDir, { recursive: true });
230
- }
231
- // Unload if already loaded
232
- try {
233
- (0, child_process_1.execSync)(`launchctl unload "${plistPath}" 2>/dev/null`, { encoding: 'utf-8' });
234
- if (verbose) {
235
- console.log(chalk_1.default.gray(` Unloaded existing: ${plistName}`));
236
- }
237
- }
238
- catch {
239
- // Ignore if not loaded
240
- }
241
- // Write plist
242
- fs.writeFileSync(plistPath, plistContent);
243
- if (verbose) {
244
- console.log(chalk_1.default.gray(` Created: ${plistPath}`));
245
- }
246
- // Load the service
247
- try {
248
- (0, child_process_1.execSync)(`launchctl load "${plistPath}"`, { encoding: 'utf-8' });
249
- if (verbose) {
250
- console.log(chalk_1.default.gray(` Loaded: ${plistName}`));
251
- }
252
- }
253
- catch (err) {
254
- throw new Error(`Failed to load launchd service: ${err.message}`);
255
- }
256
- // Verify it's loaded
257
- try {
258
- const output = (0, child_process_1.execSync)('launchctl list | grep dev.ekkos.agent', { encoding: 'utf-8' });
259
- if (verbose && output.trim()) {
260
- console.log(chalk_1.default.gray(` Service status: ${output.trim()}`));
261
- }
262
- }
263
- catch {
264
- // Ignore if grep finds nothing
265
- }
266
- }
267
- /**
268
- * Build plist content with proper XML escaping
269
- */
270
- function buildPlist(label, args, nodePath) {
271
- const homeDir = os.homedir();
272
- const ekkosDir = state_1.EKKOS_DIR;
273
- const nodeBinDir = path.dirname(nodePath);
274
- const launchPath = `${nodeBinDir}:${path.join(homeDir, '.local', 'bin')}:/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin`;
275
- // Build ProgramArguments array
276
- let argXml = '';
277
- for (const arg of args) {
278
- argXml += ` <string>${escapeXml(arg)}</string>\n`;
279
- }
280
- return `<?xml version="1.0" encoding="UTF-8"?>
281
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
282
- <plist version="1.0">
283
- <dict>
284
- <key>Label</key>
285
- <string>${escapeXml(label)}</string>
286
-
287
- <key>ProgramArguments</key>
288
- <array>
289
- ${argXml} </array>
290
-
291
- <!-- Run at system login and on demand -->
292
- <key>RunAtLoad</key>
293
- <true/>
294
-
295
- <!-- Keep alive: restart immediately if it exits or crashes -->
296
- <key>KeepAlive</key>
297
- <dict>
298
- <!-- Restart even if exit code is 0 (successful exit) -->
299
- <key>SuccessfulExit</key>
300
- <false/>
301
- <!-- Restart if process is terminated by signal -->
302
- <key>Crashed</key>
303
- <true/>
304
- </dict>
305
-
306
- <!-- Logging -->
307
- <key>StandardErrorPath</key>
308
- <string>${escapeXml(path.join(ekkosDir, 'agent.err.log'))}</string>
309
-
310
- <key>StandardOutPath</key>
311
- <string>${escapeXml(path.join(ekkosDir, 'agent.out.log'))}</string>
312
-
313
- <!-- Environment variables -->
314
- <key>EnvironmentVariables</key>
315
- <dict>
316
- <key>PATH</key>
317
- <string>${escapeXml(launchPath)}</string>
318
- <key>NODE_ENV</key>
319
- <string>production</string>
320
- <key>HOME</key>
321
- <string>${escapeXml(homeDir)}</string>
322
- </dict>
323
-
324
- <!-- Process management -->
325
- <key>ProcessType</key>
326
- <string>Background</string>
327
-
328
- <!-- Critical: Allow daemon to handle network reconnections -->
329
- <key>AbandonProcessGroup</key>
330
- <true/>
331
-
332
- <!-- Restart throttle: wait 10s before restarting crashed process -->
333
- <key>ThrottleInterval</key>
334
- <integer>10</integer>
335
-
336
- <!-- Higher priority for reliable connectivity -->
337
- <key>Nice</key>
338
- <integer>-5</integer>
339
-
340
- <!-- File descriptor limits -->
341
- <key>SoftResourceLimits</key>
342
- <dict>
343
- <key>NumberOfFiles</key>
344
- <integer>2048</integer>
345
- </dict>
346
-
347
- <!-- Working directory -->
348
- <key>WorkingDirectory</key>
349
- <string>${escapeXml(homeDir)}</string>
350
- </dict>
351
- </plist>`;
352
- }
353
- /**
354
- * Escape XML special characters
355
- */
356
- function escapeXml(str) {
357
- return str
358
- .replace(/&/g, '&amp;')
359
- .replace(/</g, '&lt;')
360
- .replace(/>/g, '&gt;')
361
- .replace(/"/g, '&quot;')
362
- .replace(/'/g, '&apos;');
363
- }
364
- /**
365
- * Install Windows service
366
- */
367
- async function installWindowsService(verbose) {
368
- // Windows uses a scheduled task that runs at login
369
- const taskName = 'ekkOS Agent';
370
- // Find ekkos CLI path
371
- let ekkosPath;
372
- try {
373
- ekkosPath = (0, child_process_1.execSync)('where ekkos', { encoding: 'utf-8' }).trim().split('\n')[0];
374
- }
375
- catch {
376
- // Fall back to npx
377
- ekkosPath = 'npx';
378
- }
379
- // Create scheduled task
380
- const command = ekkosPath.includes('npx')
381
- ? `npx @ekkos/cli agent daemon`
382
- : `"${ekkosPath}" agent daemon`;
383
- try {
384
- // Delete existing task
385
- (0, child_process_1.execSync)(`schtasks /delete /tn "${taskName}" /f 2>nul`, { encoding: 'utf-8' });
386
- }
387
- catch {
388
- // Ignore if doesn't exist
389
- }
390
- // Create task that runs at login
391
- (0, child_process_1.execSync)(`schtasks /create /tn "${taskName}" /tr "${command}" /sc onlogon /rl limited`, { encoding: 'utf-8' });
392
- // Start the task now
393
- (0, child_process_1.execSync)(`schtasks /run /tn "${taskName}"`, { encoding: 'utf-8' });
394
- if (verbose) {
395
- console.log(chalk_1.default.gray(` Created scheduled task: ${taskName}`));
396
- }
397
- }
398
- /**
399
- * Install Linux systemd service
400
- */
401
- async function installLinuxService(verbose) {
402
- const serviceName = 'ekkos-agent';
403
- const serviceDir = path.join(os.homedir(), '.config', 'systemd', 'user');
404
- const servicePath = path.join(serviceDir, `${serviceName}.service`);
405
- // Find ekkos CLI path
406
- let ekkosPath;
407
- try {
408
- ekkosPath = (0, child_process_1.execSync)('which ekkos', { encoding: 'utf-8' }).trim();
409
- }
410
- catch {
411
- ekkosPath = 'npx @ekkos/cli';
412
- }
413
- const serviceContent = `[Unit]
414
- Description=ekkOS Remote Terminal Agent
415
- After=network.target
416
-
417
- [Service]
418
- Type=simple
419
- ExecStart=${process.execPath} ${ekkosPath} agent daemon
420
- Restart=always
421
- RestartSec=10
422
- StandardOutput=append:${path.join(state_1.EKKOS_DIR, 'agent.out.log')}
423
- StandardError=append:${path.join(state_1.EKKOS_DIR, 'agent.err.log')}
424
-
425
- [Install]
426
- WantedBy=default.target
427
- `;
428
- // Ensure directory exists
429
- if (!fs.existsSync(serviceDir)) {
430
- fs.mkdirSync(serviceDir, { recursive: true });
431
- }
432
- // Write service file
433
- fs.writeFileSync(servicePath, serviceContent);
434
- // Reload systemd and enable service
435
- (0, child_process_1.execSync)('systemctl --user daemon-reload', { encoding: 'utf-8' });
436
- (0, child_process_1.execSync)(`systemctl --user enable ${serviceName}`, { encoding: 'utf-8' });
437
- (0, child_process_1.execSync)(`systemctl --user restart ${serviceName}`, { encoding: 'utf-8' });
438
- if (verbose) {
439
- console.log(chalk_1.default.gray(` Created: ${servicePath}`));
440
- console.log(chalk_1.default.gray(` Enabled and started: ${serviceName}`));
441
- }
442
- }
443
- /**
444
- * Verify agent is connected
445
- */
446
- async function verifyConnection(deviceInfo, authToken) {
447
- // Wait a bit for agent to start
448
- await new Promise(resolve => setTimeout(resolve, 3000));
449
- // Check device status
450
- const response = await fetch(`${RELAY_API_URL}/api/v1/relay/devices/${(await (0, state_1.getState)())?.userId}`, {
451
- headers: {
452
- 'Authorization': `Bearer ${authToken}`,
453
- },
454
- });
455
- if (!response.ok) {
456
- return false;
457
- }
458
- const data = await response.json();
459
- const device = data.devices?.find((d) => d.deviceId === deviceInfo.deviceId);
460
- return device?.online === true;
461
- }
462
- /**
463
- * Main setup command
464
- */
465
- async function setupRemote(options = {}) {
466
- const verbose = options.verbose || false;
467
- console.log('');
468
- console.log(chalk_1.default.cyan.bold(' 🔧 ekkOS Remote Setup'));
469
- console.log('');
470
- // Step 1: Check if logged in
471
- let authToken = (0, state_1.getAuthToken)();
472
- if (!authToken) {
473
- console.log(chalk_1.default.yellow(' You need to log in first.'));
474
- console.log('');
475
- await (0, init_1.init)({ ide: 'claude' });
476
- authToken = (0, state_1.getAuthToken)();
477
- if (!authToken) {
478
- console.log(chalk_1.default.red(' Failed to authenticate. Please run `ekkos init` first.'));
479
- process.exit(1);
480
- }
481
- }
482
- const state = (0, state_1.getState)();
483
- console.log(chalk_1.default.green(` ✓ Logged in as ${state?.userEmail || 'unknown'}`));
484
- // Step 2: Get or create device info
485
- const deviceInfo = getOrCreateDeviceInfo();
486
- console.log(chalk_1.default.green(` ✓ Device: ${deviceInfo.deviceName} (${deviceInfo.arch})`));
487
- // Step 3: Check if already paired
488
- const deviceFilePath = path.join(state_1.EKKOS_DIR, 'device.json');
489
- const deviceData = JSON.parse(fs.readFileSync(deviceFilePath, 'utf-8'));
490
- if (deviceData.deviceToken && !options.force) {
491
- console.log(chalk_1.default.green(' ✓ Device already paired'));
492
- }
493
- else {
494
- // Request pairing code
495
- console.log('');
496
- console.log(chalk_1.default.cyan(' Requesting pairing code...'));
497
- let pairingResponse;
498
- try {
499
- pairingResponse = await requestPairingCode(deviceInfo, authToken);
500
- }
501
- catch (err) {
502
- console.log(chalk_1.default.red(` Error: ${err.message}`));
503
- process.exit(1);
504
- }
505
- // Open browser for approval
506
- const verificationUrl = pairingResponse.verificationUrl || `${PLATFORM_URL}/verify/${pairingResponse.userCode}`;
507
- console.log('');
508
- console.log(chalk_1.default.white(` Verification code: ${chalk_1.default.bold.yellow(pairingResponse.userCode)}`));
509
- console.log(chalk_1.default.gray(` Opening browser to approve...`));
510
- console.log('');
511
- try {
512
- await (0, open_1.default)(verificationUrl);
513
- }
514
- catch {
515
- console.log(chalk_1.default.yellow(` Could not open browser. Please visit:`));
516
- console.log(chalk_1.default.cyan(` ${verificationUrl}`));
517
- }
518
- // Poll for approval
519
- console.log(chalk_1.default.gray(' Waiting for approval'));
520
- process.stdout.write(' ');
521
- try {
522
- const result = await pollForApproval(pairingResponse.deviceCode, authToken);
523
- console.log('');
524
- if (!result.approved) {
525
- console.log(chalk_1.default.red(' Pairing was denied.'));
526
- process.exit(1);
527
- }
528
- // Save device token
529
- deviceData.deviceToken = result.deviceToken;
530
- deviceData.pairedAt = new Date().toISOString();
531
- fs.writeFileSync(deviceFilePath, JSON.stringify(deviceData, null, 2));
532
- console.log(chalk_1.default.green(' ✓ Device paired'));
533
- }
534
- catch (err) {
535
- console.log('');
536
- console.log(chalk_1.default.red(` Error: ${err.message}`));
537
- process.exit(1);
538
- }
539
- }
540
- // Step 4: Install service (unless skipped)
541
- if (!options.skipService) {
542
- console.log(chalk_1.default.cyan(' Installing agent service...'));
543
- try {
544
- await installService(verbose);
545
- console.log(chalk_1.default.green(' ✓ Agent installed and running'));
546
- }
547
- catch (err) {
548
- console.log(chalk_1.default.yellow(` Warning: Could not install service: ${err.message}`));
549
- console.log(chalk_1.default.gray(' You can start the agent manually with: ekkos agent start'));
550
- }
551
- }
552
- // Step 5: Verify connection
553
- console.log(chalk_1.default.cyan(' Verifying connection...'));
554
- const connected = await verifyConnection(deviceInfo, authToken);
555
- if (connected) {
556
- console.log(chalk_1.default.green(' ✓ Connected to ekkOS cloud'));
557
- }
558
- else {
559
- console.log(chalk_1.default.yellow(' ⚠ Agent not connected yet (may take a moment)'));
560
- }
561
- // Success message
562
- console.log('');
563
- console.log(chalk_1.default.green.bold(' 🎉 Setup complete!'));
564
- console.log('');
565
- console.log(chalk_1.default.white(' Access your terminal from anywhere at:'));
566
- console.log(chalk_1.default.cyan(` ${PLATFORM_URL}/dashboard/terminal`));
567
- console.log('');
568
- console.log(chalk_1.default.gray(` Your device will appear as "${deviceInfo.deviceName}" in the device list.`));
569
- console.log(chalk_1.default.gray(' The agent runs in background and auto-starts on boot.'));
570
- console.log('');
571
- console.log(chalk_1.default.dim(' How it works:'));
572
- console.log(chalk_1.default.dim(' • Claude Code runs on THIS machine (uses your subscription)'));
573
- console.log(chalk_1.default.dim(' • ekkOS provides secure relay to access it from any browser'));
574
- console.log(chalk_1.default.dim(' • Your code/files stay local - only terminal I/O is relayed'));
575
- console.log(chalk_1.default.dim(' • ekkOS learns from every session - faster, smarter, better over time'));
576
- console.log('');
577
- console.log(chalk_1.default.gray(' Commands:'));
578
- console.log(chalk_1.default.gray(' ekkos agent status - Check agent status'));
579
- console.log(chalk_1.default.gray(' ekkos agent stop - Stop agent temporarily'));
580
- console.log(chalk_1.default.gray(' ekkos agent uninstall - Remove agent completely'));
581
- console.log('');
582
- }
@@ -1,10 +0,0 @@
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>;