teleportation-cli 1.1.4 → 1.2.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 (48) hide show
  1. package/.claude/hooks/config-loader.mjs +88 -34
  2. package/.claude/hooks/permission_request.mjs +392 -82
  3. package/.claude/hooks/post_tool_use.mjs +90 -0
  4. package/.claude/hooks/pre_tool_use.mjs +247 -305
  5. package/.claude/hooks/session-register.mjs +94 -105
  6. package/.claude/hooks/session_end.mjs +41 -42
  7. package/.claude/hooks/session_start.mjs +45 -60
  8. package/.claude/hooks/stop.mjs +752 -99
  9. package/.claude/hooks/user_prompt_submit.mjs +26 -3
  10. package/README.md +7 -0
  11. package/lib/auth/api-key.js +12 -0
  12. package/lib/auth/token-refresh.js +286 -0
  13. package/lib/cli/daemon-commands.js +1 -1
  14. package/lib/cli/teleport-commands.js +469 -0
  15. package/lib/daemon/daemon-v2.js +104 -0
  16. package/lib/daemon/lifecycle.js +56 -171
  17. package/lib/daemon/response-classifier.js +15 -1
  18. package/lib/daemon/services/index.js +3 -0
  19. package/lib/daemon/services/polling-service.js +173 -0
  20. package/lib/daemon/services/queue-service.js +318 -0
  21. package/lib/daemon/services/session-service.js +115 -0
  22. package/lib/daemon/state.js +35 -0
  23. package/lib/daemon/task-executor-v2.js +413 -0
  24. package/lib/daemon/task-executor.js +1235 -0
  25. package/lib/daemon/teleportation-daemon.js +770 -25
  26. package/lib/daemon/timeline-analyzer.js +215 -0
  27. package/lib/daemon/transcript-ingestion.js +696 -0
  28. package/lib/daemon/utils.js +91 -0
  29. package/lib/install/installer.js +184 -20
  30. package/lib/install/uhr-installer.js +136 -0
  31. package/lib/remote/providers/base-provider.js +46 -0
  32. package/lib/remote/providers/daytona-provider.js +58 -0
  33. package/lib/remote/providers/provider-factory.js +90 -19
  34. package/lib/remote/providers/sprites-provider.js +711 -0
  35. package/lib/teleport/exporters/claude-exporter.js +302 -0
  36. package/lib/teleport/exporters/gemini-exporter.js +307 -0
  37. package/lib/teleport/exporters/index.js +93 -0
  38. package/lib/teleport/exporters/interface.js +153 -0
  39. package/lib/teleport/fork-tracker.js +415 -0
  40. package/lib/teleport/git-committer.js +337 -0
  41. package/lib/teleport/index.js +48 -0
  42. package/lib/teleport/manager.js +620 -0
  43. package/lib/teleport/session-capture.js +282 -0
  44. package/package.json +11 -5
  45. package/teleportation-cli.cjs +632 -451
  46. package/.claude/hooks/heartbeat.mjs +0 -396
  47. package/lib/daemon/agentic-executor.js +0 -803
  48. package/lib/daemon/pid-manager.js +0 -160
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
  // Shared config loader for all hooks
3
3
  // Reads from encrypted credentials (~/.teleportation/credentials), then ~/.teleportation-config.json, then env vars
4
+ // PRD-0019: Supports JWT authentication with automatic token refresh
4
5
 
5
6
  import { readFile } from 'node:fs/promises';
6
7
  import { homedir } from 'node:os';
@@ -12,6 +13,33 @@ import { fileURLToPath } from 'node:url';
12
13
  const __filename = fileURLToPath(import.meta.url);
13
14
  const __dirname = dirname(__filename);
14
15
 
16
+ // Path resolution helper for auth modules
17
+ const AUTH_MODULE_PATHS = [
18
+ // If hook is still in project directory
19
+ () => join(process.cwd(), 'lib', 'auth'),
20
+ // If installed globally, try common locations
21
+ () => join(homedir(), '.teleportation', 'lib', 'auth'),
22
+ // Try relative to hook location (if hooks are symlinked)
23
+ () => join(__dirname, '..', '..', 'lib', 'auth')
24
+ ];
25
+
26
+ /**
27
+ * Try to import a module from multiple possible paths
28
+ */
29
+ async function tryImportModule(moduleName) {
30
+ for (const getPath of AUTH_MODULE_PATHS) {
31
+ const modulePath = join(getPath(), moduleName);
32
+ try {
33
+ const module = await import(modulePath);
34
+ return module;
35
+ } catch (e) {
36
+ // Try next path
37
+ continue;
38
+ }
39
+ }
40
+ return null;
41
+ }
42
+
15
43
  export async function loadConfig() {
16
44
  // Test override: allow forcing config to be loaded from environment variables only
17
45
  // This is useful for unit tests that mock the relay API.
@@ -20,46 +48,70 @@ export async function loadConfig() {
20
48
  relayApiUrl: env.RELAY_API_URL || '',
21
49
  relayApiKey: env.RELAY_API_KEY || '',
22
50
  userToken: env.DETACH_USER_TOKEN || '',
23
- slackWebhookUrl: env.SLACK_WEBHOOK_URL || ''
51
+ slackWebhookUrl: env.SLACK_WEBHOOK_URL || '',
52
+ authMethod: 'env'
24
53
  };
25
54
  }
26
55
 
27
- // Priority 1: Try to load from encrypted credentials file
56
+ // Priority 1: Try JWT authentication (PRD-0019)
57
+ // This provides automatic token refresh for short-lived access tokens
28
58
  try {
29
- // Try multiple possible paths for the credential manager
30
- const possiblePaths = [
31
- // If hook is still in project directory
32
- join(process.cwd(), 'lib', 'auth', 'credentials.js'),
33
- // If installed globally, try common locations
34
- join(homedir(), '.teleportation', 'lib', 'auth', 'credentials.js'),
35
- // Development path (if running from workspace)
36
- join(homedir(), 'dev_env', 'teleporter', 'teleportation', 'lib', 'auth', 'credentials.js'),
37
- // Try relative to hook location (if hooks are symlinked)
38
- join(__dirname, '..', '..', 'lib', 'auth', 'credentials.js')
39
- ];
40
-
41
- let CredentialManager = null;
42
- for (const credentialsPath of possiblePaths) {
43
- try {
44
- const module = await import(credentialsPath);
45
- CredentialManager = module.CredentialManager;
46
- if (CredentialManager) break;
47
- } catch (e) {
48
- // Try next path
49
- continue;
59
+ const tokenRefreshModule = await tryImportModule('token-refresh.js');
60
+ if (tokenRefreshModule && tokenRefreshModule.getValidAccessToken) {
61
+ const { getValidAccessToken, getAuthMethod } = tokenRefreshModule;
62
+
63
+ // Check if JWT credentials are available
64
+ const authInfo = await getAuthMethod();
65
+ if (authInfo.method === 'jwt') {
66
+ // Get a valid access token (refreshes automatically if needed)
67
+ const accessToken = await getValidAccessToken();
68
+
69
+ // Load credentials for other config values
70
+ const credentialsModule = await tryImportModule('credentials.js');
71
+ let relayApiUrl = '';
72
+ let slackWebhookUrl = '';
73
+
74
+ if (credentialsModule && credentialsModule.CredentialManager) {
75
+ const manager = new credentialsModule.CredentialManager();
76
+ const credentials = await manager.load();
77
+ if (credentials) {
78
+ relayApiUrl = credentials.relayApiUrl || credentials.relay_api_url || '';
79
+ slackWebhookUrl = credentials.slackWebhookUrl || credentials.slack_webhook_url || '';
80
+ }
81
+ }
82
+
83
+ return {
84
+ relayApiUrl,
85
+ relayApiKey: accessToken, // JWT access token used as Bearer token
86
+ userToken: '',
87
+ slackWebhookUrl,
88
+ authMethod: 'jwt'
89
+ };
50
90
  }
51
91
  }
52
-
53
- if (CredentialManager) {
54
- const manager = new CredentialManager();
92
+ } catch (e) {
93
+ // JWT auth failed (token refresh error, etc.) - fall back to legacy auth
94
+ // Common errors: session expired, network issues, etc.
95
+ if (env.DEBUG) {
96
+ console.error(`[ConfigLoader] JWT auth failed: ${e.message}`);
97
+ }
98
+ }
99
+
100
+ // Priority 2: Try to load from encrypted credentials file (legacy API key)
101
+ try {
102
+ const credentialsModule = await tryImportModule('credentials.js');
103
+
104
+ if (credentialsModule && credentialsModule.CredentialManager) {
105
+ const manager = new credentialsModule.CredentialManager();
55
106
  const credentials = await manager.load();
56
-
107
+
57
108
  if (credentials) {
58
109
  return {
59
110
  relayApiUrl: credentials.relayApiUrl || credentials.relay_api_url || '',
60
111
  relayApiKey: credentials.relayApiKey || credentials.apiKey || credentials.relay_api_key || '',
61
112
  userToken: credentials.userToken || credentials.user_token || '',
62
- slackWebhookUrl: credentials.slackWebhookUrl || credentials.slack_webhook_url || ''
113
+ slackWebhookUrl: credentials.slackWebhookUrl || credentials.slack_webhook_url || '',
114
+ authMethod: 'api-key'
63
115
  };
64
116
  }
65
117
  }
@@ -67,9 +119,9 @@ export async function loadConfig() {
67
119
  // Credential manager not available or credentials don't exist, continue to fallback
68
120
  }
69
121
 
70
- // Priority 2: Try to load from legacy config file
122
+ // Priority 3: Try to load from legacy config file
71
123
  const configPath = join(homedir(), '.teleportation-config.json');
72
-
124
+
73
125
  try {
74
126
  const content = await readFile(configPath, 'utf8');
75
127
  const config = JSON.parse(content);
@@ -77,17 +129,19 @@ export async function loadConfig() {
77
129
  relayApiUrl: config.relay_api_url || '',
78
130
  relayApiKey: config.relay_api_key || '',
79
131
  userToken: config.user_token || '',
80
- slackWebhookUrl: config.slack_webhook_url || ''
132
+ slackWebhookUrl: config.slack_webhook_url || '',
133
+ authMethod: 'legacy-config'
81
134
  };
82
135
  } catch (e) {
83
136
  // Config file doesn't exist, continue to fallback
84
137
  }
85
-
86
- // Priority 3: Fall back to environment variables
138
+
139
+ // Priority 4: Fall back to environment variables
87
140
  return {
88
141
  relayApiUrl: env.RELAY_API_URL || '',
89
142
  relayApiKey: env.RELAY_API_KEY || '',
90
143
  userToken: env.DETACH_USER_TOKEN || '',
91
- slackWebhookUrl: env.SLACK_WEBHOOK_URL || ''
144
+ slackWebhookUrl: env.SLACK_WEBHOOK_URL || '',
145
+ authMethod: 'env'
92
146
  };
93
147
  }