teleportation-cli 1.0.0 → 1.0.2
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/.claude/hooks/heartbeat.mjs +67 -2
- package/.claude/hooks/permission_request.mjs +55 -26
- package/.claude/hooks/pre_tool_use.mjs +29 -2
- package/.claude/hooks/session-register.mjs +64 -5
- package/.claude/hooks/stop.mjs +205 -1
- package/.claude/hooks/user_prompt_submit.mjs +111 -0
- package/README.md +36 -12
- package/lib/auth/claude-key-extractor.js +196 -0
- package/lib/auth/credentials.js +7 -2
- package/lib/cli/remote-commands.js +649 -0
- package/lib/daemon/teleportation-daemon.js +131 -41
- package/lib/install/installer.js +22 -7
- package/lib/machine-coders/claude-code-adapter.js +191 -37
- package/lib/remote/code-sync.js +213 -0
- package/lib/remote/init-script-robust.js +187 -0
- package/lib/remote/liveport-client.js +417 -0
- package/lib/remote/orchestrator.js +480 -0
- package/lib/remote/pr-creator.js +382 -0
- package/lib/remote/providers/base-provider.js +407 -0
- package/lib/remote/providers/daytona-provider.js +506 -0
- package/lib/remote/providers/fly-provider.js +611 -0
- package/lib/remote/providers/provider-factory.js +228 -0
- package/lib/remote/results-delivery.js +333 -0
- package/lib/remote/session-manager.js +273 -0
- package/lib/remote/state-capture.js +324 -0
- package/lib/remote/vault-client.js +478 -0
- package/lib/session/metadata.js +80 -49
- package/lib/session/mute-checker.js +2 -1
- package/lib/utils/vault-errors.js +353 -0
- package/package.json +5 -5
- package/teleportation-cli.cjs +417 -7
package/teleportation-cli.cjs
CHANGED
|
@@ -207,6 +207,7 @@ function commandHelp() {
|
|
|
207
207
|
|
|
208
208
|
console.log(c.yellow('Authentication:'));
|
|
209
209
|
console.log(' ' + c.green('login') + ' Authenticate with API key or token');
|
|
210
|
+
console.log(' ' + c.green('github connect') + ' Save GitHub token for repo access (used by remote sessions)');
|
|
210
211
|
console.log(' ' + c.green('logout') + ' Clear saved credentials\n');
|
|
211
212
|
|
|
212
213
|
console.log(c.yellow('Setup Commands:'));
|
|
@@ -248,6 +249,14 @@ function commandHelp() {
|
|
|
248
249
|
console.log(' ' + c.green('config edit') + ' Open config in editor');
|
|
249
250
|
console.log(' ' + c.green('env') + ' Show environment variables\n');
|
|
250
251
|
|
|
252
|
+
console.log(c.yellow('Remote Sessions:'));
|
|
253
|
+
console.log(' ' + c.green('remote start') + ' Start a remote AI agent session');
|
|
254
|
+
console.log(' ' + c.green('remote list') + ' List all remote sessions');
|
|
255
|
+
console.log(' ' + c.green('remote status') + ' Show remote session details');
|
|
256
|
+
console.log(' ' + c.green('remote logs') + ' View logs from remote session');
|
|
257
|
+
console.log(' ' + c.green('remote pull') + ' Pull results from remote session');
|
|
258
|
+
console.log(' ' + c.green('remote help') + ' Show remote commands help\n');
|
|
259
|
+
|
|
251
260
|
console.log(c.yellow('Session Isolation:'));
|
|
252
261
|
console.log(' ' + c.green('worktree create') + ' Create isolated worktree for a session');
|
|
253
262
|
console.log(' ' + c.green('worktree list') + ' List all session worktrees');
|
|
@@ -385,7 +394,7 @@ async function commandSetup() {
|
|
|
385
394
|
}
|
|
386
395
|
|
|
387
396
|
// Step 1: Authentication
|
|
388
|
-
console.log('\n' + c.purple('Step 1 of
|
|
397
|
+
console.log('\n' + c.purple('Step 1 of 5: Authentication\n'));
|
|
389
398
|
console.log(' You\'ll need to sign in to get an API key.\n');
|
|
390
399
|
|
|
391
400
|
// Try to open browser
|
|
@@ -437,7 +446,7 @@ async function commandSetup() {
|
|
|
437
446
|
console.log(c.green(' ✅ API key validated successfully!'));
|
|
438
447
|
|
|
439
448
|
// Step 2: Configuration
|
|
440
|
-
console.log('\n' + c.purple('Step 2 of
|
|
449
|
+
console.log('\n' + c.purple('Step 2 of 5: Configuration\n'));
|
|
441
450
|
console.log(` Relay URL: ${c.cyan(relayUrl)}`);
|
|
442
451
|
|
|
443
452
|
// Test relay connectivity
|
|
@@ -484,7 +493,7 @@ async function commandSetup() {
|
|
|
484
493
|
}
|
|
485
494
|
|
|
486
495
|
// Step 3: Install Hooks
|
|
487
|
-
console.log('\n' + c.purple('Step 3 of
|
|
496
|
+
console.log('\n' + c.purple('Step 3 of 5: Installing Hooks\n'));
|
|
488
497
|
console.log(' Installing Claude Code hooks to ~/.claude/hooks/');
|
|
489
498
|
|
|
490
499
|
try {
|
|
@@ -510,12 +519,37 @@ async function commandSetup() {
|
|
|
510
519
|
return;
|
|
511
520
|
}
|
|
512
521
|
|
|
513
|
-
// Step 4:
|
|
514
|
-
console.log('\n' + c.purple('Step 4 of
|
|
522
|
+
// Step 4: Start Daemon
|
|
523
|
+
console.log('\n' + c.purple('Step 4 of 5: Starting Daemon\n'));
|
|
524
|
+
console.log(' Starting the teleportation daemon for remote commands...');
|
|
525
|
+
|
|
526
|
+
try {
|
|
527
|
+
const lifecyclePath = path.join(TELEPORTATION_DIR, 'lib', 'daemon', 'lifecycle.js');
|
|
528
|
+
const { access } = await import('fs/promises');
|
|
529
|
+
try {
|
|
530
|
+
await access(lifecyclePath);
|
|
531
|
+
} catch {
|
|
532
|
+
throw new Error('Daemon module not found. Please reinstall: npm install -g teleportation-cli');
|
|
533
|
+
}
|
|
534
|
+
const { startDaemon } = await import('file://' + lifecyclePath);
|
|
535
|
+
const result = await startDaemon({ detached: true, silent: true });
|
|
536
|
+
console.log(c.green(` ✅ Daemon started (PID: ${result.pid})`));
|
|
537
|
+
} catch (e) {
|
|
538
|
+
if (e.message && e.message.includes('already running')) {
|
|
539
|
+
console.log(c.green(' ✅ Daemon already running'));
|
|
540
|
+
} else {
|
|
541
|
+
console.log(c.yellow(` ⚠️ Could not start daemon: ${e.message}`));
|
|
542
|
+
console.log(c.cyan(' You can start it manually with: teleportation daemon start'));
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// Step 5: Verification
|
|
547
|
+
console.log('\n' + c.purple('Step 5 of 5: Verification\n'));
|
|
515
548
|
console.log(c.green(' ✅ Credentials saved'));
|
|
516
549
|
console.log(c.green(' ✅ Configuration saved'));
|
|
517
550
|
console.log(c.green(' ✅ Hooks installed'));
|
|
518
551
|
console.log(c.green(' ✅ Relay connectivity confirmed'));
|
|
552
|
+
console.log(c.green(' ✅ Daemon running'));
|
|
519
553
|
|
|
520
554
|
// Success!
|
|
521
555
|
console.log('\n' + c.cyan('╭─────────────────────────────────────────────────────╮'));
|
|
@@ -1545,7 +1579,8 @@ async function commandLogin(args) {
|
|
|
1545
1579
|
|
|
1546
1580
|
// Check for existing credentials
|
|
1547
1581
|
const existing = await manager.load();
|
|
1548
|
-
|
|
1582
|
+
const hasRelayCreds = !!(existing && (existing.relayApiKey || existing.apiKey || existing.accessToken));
|
|
1583
|
+
if (hasRelayCreds) {
|
|
1549
1584
|
console.log(c.yellow('⚠️ You are already logged in.'));
|
|
1550
1585
|
console.log(c.cyan(' Run "teleportation logout" to clear existing credentials.\n'));
|
|
1551
1586
|
|
|
@@ -1608,7 +1643,9 @@ async function performLogin(manager, flags, positional) {
|
|
|
1608
1643
|
}
|
|
1609
1644
|
|
|
1610
1645
|
// Save credentials
|
|
1646
|
+
const existingCredsForMerge = await manager.load().catch(() => null);
|
|
1611
1647
|
const credentials = {
|
|
1648
|
+
...(existingCredsForMerge && typeof existingCredsForMerge === 'object' ? existingCredsForMerge : {}),
|
|
1612
1649
|
apiKey: apiKey,
|
|
1613
1650
|
relayApiUrl: relayApiUrl,
|
|
1614
1651
|
authenticatedAt: Date.now(),
|
|
@@ -1629,6 +1666,29 @@ async function performLogin(manager, flags, positional) {
|
|
|
1629
1666
|
|
|
1630
1667
|
console.log(c.green('✅ Successfully authenticated with API key!\n'));
|
|
1631
1668
|
console.log(c.cyan('Credentials saved to ~/.teleportation/credentials\n'));
|
|
1669
|
+
|
|
1670
|
+
// Auto-start daemon
|
|
1671
|
+
console.log(c.cyan('Starting daemon for remote commands...'));
|
|
1672
|
+
try {
|
|
1673
|
+
const lifecyclePath = path.join(TELEPORTATION_DIR, 'lib', 'daemon', 'lifecycle.js');
|
|
1674
|
+
const { access } = await import('fs/promises');
|
|
1675
|
+
try {
|
|
1676
|
+
await access(lifecyclePath);
|
|
1677
|
+
} catch {
|
|
1678
|
+
throw new Error('Daemon module not found. Please reinstall: npm install -g teleportation-cli');
|
|
1679
|
+
}
|
|
1680
|
+
const { startDaemon } = await import('file://' + lifecyclePath);
|
|
1681
|
+
const result = await startDaemon({ detached: true, silent: true });
|
|
1682
|
+
console.log(c.green(`✅ Daemon started (PID: ${result.pid})\n`));
|
|
1683
|
+
} catch (e) {
|
|
1684
|
+
if (e.message && e.message.includes('already running')) {
|
|
1685
|
+
console.log(c.green('✅ Daemon already running\n'));
|
|
1686
|
+
} else {
|
|
1687
|
+
console.log(c.yellow(`⚠️ Could not start daemon: ${e.message}`));
|
|
1688
|
+
console.log(c.cyan('You can start it manually with: teleportation daemon start\n'));
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1632
1692
|
console.log(c.yellow('⚠️ Restart Claude Code to apply changes to current session.\n'));
|
|
1633
1693
|
return;
|
|
1634
1694
|
} catch (error) {
|
|
@@ -1643,7 +1703,9 @@ async function performLogin(manager, flags, positional) {
|
|
|
1643
1703
|
|
|
1644
1704
|
try {
|
|
1645
1705
|
// Save credentials with token
|
|
1706
|
+
const existingCredsForMerge = await manager.load().catch(() => null);
|
|
1646
1707
|
const credentials = {
|
|
1708
|
+
...(existingCredsForMerge && typeof existingCredsForMerge === 'object' ? existingCredsForMerge : {}),
|
|
1647
1709
|
accessToken: token,
|
|
1648
1710
|
relayApiUrl: relayApiUrl,
|
|
1649
1711
|
authenticatedAt: Date.now(),
|
|
@@ -1664,6 +1726,29 @@ async function performLogin(manager, flags, positional) {
|
|
|
1664
1726
|
|
|
1665
1727
|
console.log(c.green('✅ Successfully authenticated with token!\n'));
|
|
1666
1728
|
console.log(c.cyan('Credentials saved to ~/.teleportation/credentials\n'));
|
|
1729
|
+
|
|
1730
|
+
// Auto-start daemon
|
|
1731
|
+
console.log(c.cyan('Starting daemon for remote commands...'));
|
|
1732
|
+
try {
|
|
1733
|
+
const lifecyclePath = path.join(TELEPORTATION_DIR, 'lib', 'daemon', 'lifecycle.js');
|
|
1734
|
+
const { access } = await import('fs/promises');
|
|
1735
|
+
try {
|
|
1736
|
+
await access(lifecyclePath);
|
|
1737
|
+
} catch {
|
|
1738
|
+
throw new Error('Daemon module not found. Please reinstall: npm install -g teleportation-cli');
|
|
1739
|
+
}
|
|
1740
|
+
const { startDaemon } = await import('file://' + lifecyclePath);
|
|
1741
|
+
const result = await startDaemon({ detached: true, silent: true });
|
|
1742
|
+
console.log(c.green(`✅ Daemon started (PID: ${result.pid})\n`));
|
|
1743
|
+
} catch (e) {
|
|
1744
|
+
if (e.message && e.message.includes('already running')) {
|
|
1745
|
+
console.log(c.green('✅ Daemon already running\n'));
|
|
1746
|
+
} else {
|
|
1747
|
+
console.log(c.yellow(`⚠️ Could not start daemon: ${e.message}`));
|
|
1748
|
+
console.log(c.cyan('You can start it manually with: teleportation daemon start\n'));
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1667
1752
|
console.log(c.yellow('⚠️ Restart Claude Code to apply changes to current session.\n'));
|
|
1668
1753
|
return;
|
|
1669
1754
|
} catch (error) {
|
|
@@ -1709,7 +1794,9 @@ async function performLogin(manager, flags, positional) {
|
|
|
1709
1794
|
}
|
|
1710
1795
|
|
|
1711
1796
|
// Save credentials
|
|
1797
|
+
const existingCredsForMerge = await manager.load().catch(() => null);
|
|
1712
1798
|
const credentials = {
|
|
1799
|
+
...(existingCredsForMerge && typeof existingCredsForMerge === 'object' ? existingCredsForMerge : {}),
|
|
1713
1800
|
apiKey: apiKey,
|
|
1714
1801
|
relayApiUrl: relayApiUrl,
|
|
1715
1802
|
authenticatedAt: Date.now(),
|
|
@@ -1719,6 +1806,29 @@ async function performLogin(manager, flags, positional) {
|
|
|
1719
1806
|
await manager.save(credentials);
|
|
1720
1807
|
console.log(c.green('✅ Successfully authenticated!\n'));
|
|
1721
1808
|
console.log(c.cyan('Credentials saved to ~/.teleportation/credentials\n'));
|
|
1809
|
+
|
|
1810
|
+
// Auto-start daemon
|
|
1811
|
+
console.log(c.cyan('Starting daemon for remote commands...'));
|
|
1812
|
+
try {
|
|
1813
|
+
const lifecyclePath = path.join(TELEPORTATION_DIR, 'lib', 'daemon', 'lifecycle.js');
|
|
1814
|
+
const { access } = await import('fs/promises');
|
|
1815
|
+
try {
|
|
1816
|
+
await access(lifecyclePath);
|
|
1817
|
+
} catch {
|
|
1818
|
+
throw new Error('Daemon module not found. Please reinstall: npm install -g teleportation-cli');
|
|
1819
|
+
}
|
|
1820
|
+
const { startDaemon } = await import('file://' + lifecyclePath);
|
|
1821
|
+
const result = await startDaemon({ detached: true, silent: true });
|
|
1822
|
+
console.log(c.green(`✅ Daemon started (PID: ${result.pid})\n`));
|
|
1823
|
+
} catch (e) {
|
|
1824
|
+
if (e.message && e.message.includes('already running')) {
|
|
1825
|
+
console.log(c.green('✅ Daemon already running\n'));
|
|
1826
|
+
} else {
|
|
1827
|
+
console.log(c.yellow(`⚠️ Could not start daemon: ${e.message}`));
|
|
1828
|
+
console.log(c.cyan('You can start it manually with: teleportation daemon start\n'));
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1722
1832
|
resolve();
|
|
1723
1833
|
} catch (error) {
|
|
1724
1834
|
console.log(c.red(`❌ Error: ${error.message}\n`));
|
|
@@ -1880,6 +1990,128 @@ async function commandLogout() {
|
|
|
1880
1990
|
});
|
|
1881
1991
|
}
|
|
1882
1992
|
|
|
1993
|
+
async function validateGitHubToken(token) {
|
|
1994
|
+
const response = await fetch('https://api.github.com/user', {
|
|
1995
|
+
headers: {
|
|
1996
|
+
'Authorization': `Bearer ${token}`,
|
|
1997
|
+
'User-Agent': 'teleportation-cli'
|
|
1998
|
+
}
|
|
1999
|
+
});
|
|
2000
|
+
|
|
2001
|
+
if (!response.ok) {
|
|
2002
|
+
let message = response.statusText;
|
|
2003
|
+
try {
|
|
2004
|
+
const body = await response.json();
|
|
2005
|
+
message = body?.message || message;
|
|
2006
|
+
} catch {
|
|
2007
|
+
// ignore
|
|
2008
|
+
}
|
|
2009
|
+
throw new Error(`GitHub token validation failed (${response.status}): ${message}`);
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
return response.json();
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
async function commandGithub(args) {
|
|
2016
|
+
const subCommand = args[0] || 'help';
|
|
2017
|
+
const { flags } = parseFlags(args.slice(1));
|
|
2018
|
+
|
|
2019
|
+
const manager = await loadCredentialManager();
|
|
2020
|
+
if (!manager) {
|
|
2021
|
+
console.log(c.red('❌ Failed to load credential manager'));
|
|
2022
|
+
process.exit(1);
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
if (subCommand === 'connect') {
|
|
2026
|
+
let token = flags.token || flags.t;
|
|
2027
|
+
|
|
2028
|
+
if (!token) {
|
|
2029
|
+
const readline = require('readline').createInterface({
|
|
2030
|
+
input: process.stdin,
|
|
2031
|
+
output: process.stdout
|
|
2032
|
+
});
|
|
2033
|
+
|
|
2034
|
+
token = await new Promise((resolve) => {
|
|
2035
|
+
readline.question('Enter your GitHub token (fine-grained PAT recommended): ', (answer) => {
|
|
2036
|
+
readline.close();
|
|
2037
|
+
resolve(answer?.trim() || '');
|
|
2038
|
+
});
|
|
2039
|
+
});
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
if (!token) {
|
|
2043
|
+
console.log(c.yellow('Connect cancelled.\n'));
|
|
2044
|
+
return;
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
try {
|
|
2048
|
+
console.log(c.yellow('Validating GitHub token...\n'));
|
|
2049
|
+
const user = await validateGitHubToken(token);
|
|
2050
|
+
|
|
2051
|
+
const existing = await manager.load().catch(() => null);
|
|
2052
|
+
const next = {
|
|
2053
|
+
...(existing && typeof existing === 'object' ? existing : {}),
|
|
2054
|
+
githubToken: token,
|
|
2055
|
+
githubUser: user?.login || '',
|
|
2056
|
+
githubConnectedAt: Date.now()
|
|
2057
|
+
};
|
|
2058
|
+
|
|
2059
|
+
await manager.save(next);
|
|
2060
|
+
loadedCredentials = next;
|
|
2061
|
+
|
|
2062
|
+
console.log(c.green('✅ GitHub connected!\n'));
|
|
2063
|
+
if (user?.login) {
|
|
2064
|
+
console.log(c.cyan(`GitHub user: ${user.login}`));
|
|
2065
|
+
}
|
|
2066
|
+
console.log(c.cyan('GitHub token saved to ~/.teleportation/credentials\n'));
|
|
2067
|
+
return;
|
|
2068
|
+
} catch (error) {
|
|
2069
|
+
console.log(c.red(`❌ Error: ${error.message}\n`));
|
|
2070
|
+
process.exit(1);
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
if (subCommand === 'status') {
|
|
2075
|
+
const existing = await manager.load().catch(() => null);
|
|
2076
|
+
const token = existing?.githubToken;
|
|
2077
|
+
console.log(c.yellow('GitHub Credentials:\n'));
|
|
2078
|
+
console.log(' Connected:', token ? c.green('yes') : c.red('no'));
|
|
2079
|
+
if (token) {
|
|
2080
|
+
console.log(' Token:', '***' + token.slice(-4));
|
|
2081
|
+
}
|
|
2082
|
+
if (existing?.githubUser) {
|
|
2083
|
+
console.log(' User:', existing.githubUser);
|
|
2084
|
+
}
|
|
2085
|
+
console.log();
|
|
2086
|
+
return;
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
if (subCommand === 'disconnect') {
|
|
2090
|
+
const existing = await manager.load().catch(() => null);
|
|
2091
|
+
if (!existing || !existing.githubToken) {
|
|
2092
|
+
console.log(c.yellow('⚠️ No GitHub token saved.\n'));
|
|
2093
|
+
return;
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2096
|
+
const next = { ...(existing && typeof existing === 'object' ? existing : {}) };
|
|
2097
|
+
delete next.githubToken;
|
|
2098
|
+
delete next.githubUser;
|
|
2099
|
+
delete next.githubConnectedAt;
|
|
2100
|
+
|
|
2101
|
+
await manager.save(next);
|
|
2102
|
+
loadedCredentials = next;
|
|
2103
|
+
|
|
2104
|
+
console.log(c.green('✅ GitHub disconnected.\n'));
|
|
2105
|
+
return;
|
|
2106
|
+
}
|
|
2107
|
+
|
|
2108
|
+
console.log(c.purple('Teleportation GitHub\n'));
|
|
2109
|
+
console.log(c.yellow('Usage:'));
|
|
2110
|
+
console.log(' teleportation github connect --token <token>');
|
|
2111
|
+
console.log(' teleportation github status');
|
|
2112
|
+
console.log(' teleportation github disconnect\n');
|
|
2113
|
+
}
|
|
2114
|
+
|
|
1883
2115
|
// Worktree/Snapshot/Session command handlers
|
|
1884
2116
|
async function commandWorktree(args) {
|
|
1885
2117
|
const cliPath = path.join(TELEPORTATION_DIR, 'lib', 'cli', 'index.js');
|
|
@@ -1920,6 +2152,170 @@ async function commandSession(args) {
|
|
|
1920
2152
|
await routeCommand(parsed);
|
|
1921
2153
|
}
|
|
1922
2154
|
|
|
2155
|
+
/**
|
|
2156
|
+
* Handle remote session commands
|
|
2157
|
+
*/
|
|
2158
|
+
async function commandRemote(args) {
|
|
2159
|
+
const subCommand = args[0] || 'help';
|
|
2160
|
+
|
|
2161
|
+
// Parse flags
|
|
2162
|
+
const { flags, positional } = parseFlags(args.slice(1));
|
|
2163
|
+
|
|
2164
|
+
try {
|
|
2165
|
+
// Dynamically import remote commands
|
|
2166
|
+
const remoteCommandsPath = path.join(TELEPORTATION_DIR, 'lib', 'cli', 'remote-commands.js');
|
|
2167
|
+
const {
|
|
2168
|
+
commandRemoteStart,
|
|
2169
|
+
commandRemoteList,
|
|
2170
|
+
commandRemoteStatus,
|
|
2171
|
+
commandRemoteLogs,
|
|
2172
|
+
commandRemotePull,
|
|
2173
|
+
commandRemoteStop,
|
|
2174
|
+
commandRemoteResume,
|
|
2175
|
+
commandRemoteDestroy
|
|
2176
|
+
} = await import('file://' + remoteCommandsPath);
|
|
2177
|
+
|
|
2178
|
+
switch (subCommand) {
|
|
2179
|
+
case 'start':
|
|
2180
|
+
// Parse command: teleportation remote start --task "description" --branch "branch-name" [--provider fly|daytona]
|
|
2181
|
+
const task = flags.task;
|
|
2182
|
+
const branch = flags.branch;
|
|
2183
|
+
const provider = flags.provider;
|
|
2184
|
+
const noPr = flags['no-pr'] || false;
|
|
2185
|
+
|
|
2186
|
+
await commandRemoteStart({
|
|
2187
|
+
task,
|
|
2188
|
+
branch,
|
|
2189
|
+
provider,
|
|
2190
|
+
noPr
|
|
2191
|
+
});
|
|
2192
|
+
break;
|
|
2193
|
+
|
|
2194
|
+
case 'list':
|
|
2195
|
+
case 'ls':
|
|
2196
|
+
// Parse command: teleportation remote list [--status running|paused|completed|failed] [--provider fly|daytona]
|
|
2197
|
+
await commandRemoteList({
|
|
2198
|
+
status: flags.status,
|
|
2199
|
+
provider: flags.provider
|
|
2200
|
+
});
|
|
2201
|
+
break;
|
|
2202
|
+
|
|
2203
|
+
case 'status':
|
|
2204
|
+
// Parse command: teleportation remote status <session-id>
|
|
2205
|
+
const statusSessionId = positional[0] || flags['session-id'] || flags.id;
|
|
2206
|
+
if (!statusSessionId) {
|
|
2207
|
+
console.log(c.red('❌ Error: Session ID is required\n'));
|
|
2208
|
+
console.log(c.cyan('Usage: teleportation remote status <session-id>\n'));
|
|
2209
|
+
process.exit(1);
|
|
2210
|
+
}
|
|
2211
|
+
await commandRemoteStatus(statusSessionId);
|
|
2212
|
+
break;
|
|
2213
|
+
|
|
2214
|
+
case 'logs':
|
|
2215
|
+
// Parse command: teleportation remote logs <session-id> [--follow] [--tail N]
|
|
2216
|
+
const logsSessionId = positional[0] || flags['session-id'] || flags.id;
|
|
2217
|
+
if (!logsSessionId) {
|
|
2218
|
+
console.log(c.red('❌ Error: Session ID is required\n'));
|
|
2219
|
+
console.log(c.cyan('Usage: teleportation remote logs <session-id> [--follow] [--tail N]\n'));
|
|
2220
|
+
process.exit(1);
|
|
2221
|
+
}
|
|
2222
|
+
await commandRemoteLogs(logsSessionId, {
|
|
2223
|
+
follow: flags.follow || false,
|
|
2224
|
+
tail: flags.tail ? parseInt(flags.tail, 10) : undefined
|
|
2225
|
+
});
|
|
2226
|
+
break;
|
|
2227
|
+
|
|
2228
|
+
case 'pull':
|
|
2229
|
+
// Parse command: teleportation remote pull <session-id>
|
|
2230
|
+
const pullSessionId = positional[0] || flags['session-id'] || flags.id;
|
|
2231
|
+
if (!pullSessionId) {
|
|
2232
|
+
console.log(c.red('❌ Error: Session ID is required\n'));
|
|
2233
|
+
console.log(c.cyan('Usage: teleportation remote pull <session-id>\n'));
|
|
2234
|
+
process.exit(1);
|
|
2235
|
+
}
|
|
2236
|
+
await commandRemotePull(pullSessionId);
|
|
2237
|
+
break;
|
|
2238
|
+
|
|
2239
|
+
case 'stop':
|
|
2240
|
+
// Parse command: teleportation remote stop <session-id>
|
|
2241
|
+
const stopSessionId = positional[0] || flags['session-id'] || flags.id;
|
|
2242
|
+
if (!stopSessionId) {
|
|
2243
|
+
console.log(c.red('❌ Error: Session ID is required\n'));
|
|
2244
|
+
console.log(c.cyan('Usage: teleportation remote stop <session-id>\n'));
|
|
2245
|
+
process.exit(1);
|
|
2246
|
+
}
|
|
2247
|
+
await commandRemoteStop(stopSessionId);
|
|
2248
|
+
break;
|
|
2249
|
+
|
|
2250
|
+
case 'resume':
|
|
2251
|
+
// Parse command: teleportation remote resume <session-id>
|
|
2252
|
+
const resumeSessionId = positional[0] || flags['session-id'] || flags.id;
|
|
2253
|
+
if (!resumeSessionId) {
|
|
2254
|
+
console.log(c.red('❌ Error: Session ID is required\n'));
|
|
2255
|
+
console.log(c.cyan('Usage: teleportation remote resume <session-id>\n'));
|
|
2256
|
+
process.exit(1);
|
|
2257
|
+
}
|
|
2258
|
+
await commandRemoteResume(resumeSessionId);
|
|
2259
|
+
break;
|
|
2260
|
+
|
|
2261
|
+
case 'destroy':
|
|
2262
|
+
// Parse command: teleportation remote destroy <session-id> --confirm
|
|
2263
|
+
const destroySessionId = positional[0] || flags['session-id'] || flags.id;
|
|
2264
|
+
if (!destroySessionId) {
|
|
2265
|
+
console.log(c.red('❌ Error: Session ID is required\n'));
|
|
2266
|
+
console.log(c.cyan('Usage: teleportation remote destroy <session-id> --confirm\n'));
|
|
2267
|
+
process.exit(1);
|
|
2268
|
+
}
|
|
2269
|
+
await commandRemoteDestroy(destroySessionId, {
|
|
2270
|
+
confirm: flags.confirm || false
|
|
2271
|
+
});
|
|
2272
|
+
break;
|
|
2273
|
+
|
|
2274
|
+
case 'help':
|
|
2275
|
+
case '--help':
|
|
2276
|
+
case '-h':
|
|
2277
|
+
console.log(c.purple('Remote Session Commands\n'));
|
|
2278
|
+
console.log(c.cyan('Manage remote AI agent sessions running on cloud infrastructure\n'));
|
|
2279
|
+
console.log(c.yellow('Session Management:'));
|
|
2280
|
+
console.log(' ' + c.green('remote start --task "description"') + ' Start a new remote session');
|
|
2281
|
+
console.log(' ' + c.green('remote list') + ' List all remote sessions');
|
|
2282
|
+
console.log(' ' + c.green('remote status <session-id>') + ' Show session details');
|
|
2283
|
+
console.log(' ' + c.green('remote logs <session-id>') + ' View session logs');
|
|
2284
|
+
console.log(' ' + c.green('remote pull <session-id>') + ' Pull results from remote\n');
|
|
2285
|
+
console.log(c.yellow('Session Control:'));
|
|
2286
|
+
console.log(' ' + c.green('remote stop <session-id>') + ' Pause a running session');
|
|
2287
|
+
console.log(' ' + c.green('remote resume <session-id>') + ' Resume a paused session');
|
|
2288
|
+
console.log(' ' + c.green('remote destroy <session-id> --confirm') + ' Destroy session and cleanup\n');
|
|
2289
|
+
console.log(c.yellow('Options:'));
|
|
2290
|
+
console.log(' ' + c.green('--task "description"') + ' Task for the AI agent to work on');
|
|
2291
|
+
console.log(' ' + c.green('--branch "name"') + ' Git branch to use (optional)');
|
|
2292
|
+
console.log(' ' + c.green('--provider fly|daytona') + ' Force specific provider');
|
|
2293
|
+
console.log(' ' + c.green('--no-pr') + ' Skip PR creation on completion');
|
|
2294
|
+
console.log(' ' + c.green('--status running|paused') + ' Filter by status');
|
|
2295
|
+
console.log(' ' + c.green('--follow') + ' Stream logs in real-time');
|
|
2296
|
+
console.log(' ' + c.green('--tail N') + ' Show last N log lines\n');
|
|
2297
|
+
console.log(c.purple('Examples:'));
|
|
2298
|
+
console.log(' teleportation remote start --task "Implement feature X" --branch feature/x');
|
|
2299
|
+
console.log(' teleportation remote list --status running');
|
|
2300
|
+
console.log(' teleportation remote logs remote-abc123 --follow');
|
|
2301
|
+
console.log(' teleportation remote pull remote-abc123');
|
|
2302
|
+
console.log(' teleportation remote destroy remote-abc123 --confirm\n');
|
|
2303
|
+
break;
|
|
2304
|
+
|
|
2305
|
+
default:
|
|
2306
|
+
console.log(c.red(`Unknown remote command: ${subCommand}\n`));
|
|
2307
|
+
console.log(c.cyan('Run "teleportation remote help" for available commands\n'));
|
|
2308
|
+
process.exit(1);
|
|
2309
|
+
}
|
|
2310
|
+
} catch (error) {
|
|
2311
|
+
console.log(c.red(`❌ Remote command failed: ${error.message}\n`));
|
|
2312
|
+
if (process.env.DEBUG) {
|
|
2313
|
+
console.error(error.stack);
|
|
2314
|
+
}
|
|
2315
|
+
process.exit(1);
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2318
|
+
|
|
1923
2319
|
async function commandDaemon(args) {
|
|
1924
2320
|
const subCommand = args[0] || 'status';
|
|
1925
2321
|
|
|
@@ -2807,7 +3203,9 @@ const command = process.argv[2] || 'help';
|
|
|
2807
3203
|
const args = process.argv.slice(3);
|
|
2808
3204
|
|
|
2809
3205
|
// Handle async commands that need to complete before exit
|
|
2810
|
-
const asyncCommands = ['login', 'logout', 'status', 'test', 'env', 'config', 'daemon', 'away', 'back', 'daemon-status', 'command', 'inbox', 'inbox-ack', 'install-hooks', 'update'];
|
|
3206
|
+
const asyncCommands = ['login', 'logout', 'status', 'test', 'env', 'config', 'daemon', 'away', 'back', 'daemon-status', 'command', 'inbox', 'inbox-ack', 'install-hooks', 'update', 'remote'];
|
|
3207
|
+
// Keep this list in sync with switch cases below
|
|
3208
|
+
asyncCommands.push('github');
|
|
2811
3209
|
if (asyncCommands.includes(command)) {
|
|
2812
3210
|
// These commands handle their own async execution
|
|
2813
3211
|
}
|
|
@@ -2898,6 +3296,12 @@ try {
|
|
|
2898
3296
|
process.exit(1);
|
|
2899
3297
|
});
|
|
2900
3298
|
break;
|
|
3299
|
+
case 'github':
|
|
3300
|
+
commandGithub(args).catch(err => {
|
|
3301
|
+
console.error(c.red('❌ Error:'), err.message);
|
|
3302
|
+
process.exit(1);
|
|
3303
|
+
});
|
|
3304
|
+
break;
|
|
2901
3305
|
case 'daemon':
|
|
2902
3306
|
commandDaemon(args).catch(err => {
|
|
2903
3307
|
console.error(c.red('❌ Error:'), err.message);
|
|
@@ -2964,6 +3368,12 @@ try {
|
|
|
2964
3368
|
process.exit(1);
|
|
2965
3369
|
});
|
|
2966
3370
|
break;
|
|
3371
|
+
case 'remote':
|
|
3372
|
+
commandRemote(args).catch(err => {
|
|
3373
|
+
console.error(c.red('❌ Error:'), err.message);
|
|
3374
|
+
process.exit(1);
|
|
3375
|
+
});
|
|
3376
|
+
break;
|
|
2967
3377
|
case 'version':
|
|
2968
3378
|
case '--version':
|
|
2969
3379
|
case '-v':
|