episoda 0.2.5 → 0.2.8

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 (73) hide show
  1. package/dist/index.d.ts +2 -8
  2. package/dist/index.js +3735 -82
  3. package/dist/index.js.map +1 -1
  4. package/package.json +5 -4
  5. package/dist/commands/auth.d.ts +0 -22
  6. package/dist/commands/auth.d.ts.map +0 -1
  7. package/dist/commands/auth.js +0 -384
  8. package/dist/commands/auth.js.map +0 -1
  9. package/dist/commands/dev.d.ts +0 -20
  10. package/dist/commands/dev.d.ts.map +0 -1
  11. package/dist/commands/dev.js +0 -305
  12. package/dist/commands/dev.js.map +0 -1
  13. package/dist/commands/status.d.ts +0 -13
  14. package/dist/commands/status.d.ts.map +0 -1
  15. package/dist/commands/status.js +0 -102
  16. package/dist/commands/status.js.map +0 -1
  17. package/dist/commands/stop.d.ts +0 -17
  18. package/dist/commands/stop.d.ts.map +0 -1
  19. package/dist/commands/stop.js +0 -81
  20. package/dist/commands/stop.js.map +0 -1
  21. package/dist/daemon/daemon-manager.d.ts +0 -71
  22. package/dist/daemon/daemon-manager.d.ts.map +0 -1
  23. package/dist/daemon/daemon-manager.js +0 -289
  24. package/dist/daemon/daemon-manager.js.map +0 -1
  25. package/dist/daemon/daemon-process.d.ts +0 -13
  26. package/dist/daemon/daemon-process.d.ts.map +0 -1
  27. package/dist/daemon/daemon-process.js +0 -662
  28. package/dist/daemon/daemon-process.js.map +0 -1
  29. package/dist/daemon/identity-server.d.ts +0 -51
  30. package/dist/daemon/identity-server.d.ts.map +0 -1
  31. package/dist/daemon/identity-server.js +0 -162
  32. package/dist/daemon/identity-server.js.map +0 -1
  33. package/dist/daemon/machine-id.d.ts +0 -36
  34. package/dist/daemon/machine-id.d.ts.map +0 -1
  35. package/dist/daemon/machine-id.js +0 -195
  36. package/dist/daemon/machine-id.js.map +0 -1
  37. package/dist/daemon/project-tracker.d.ts +0 -92
  38. package/dist/daemon/project-tracker.d.ts.map +0 -1
  39. package/dist/daemon/project-tracker.js +0 -259
  40. package/dist/daemon/project-tracker.js.map +0 -1
  41. package/dist/dev-wrapper.d.ts +0 -88
  42. package/dist/dev-wrapper.d.ts.map +0 -1
  43. package/dist/dev-wrapper.js +0 -288
  44. package/dist/dev-wrapper.js.map +0 -1
  45. package/dist/framework-detector.d.ts +0 -29
  46. package/dist/framework-detector.d.ts.map +0 -1
  47. package/dist/framework-detector.js +0 -276
  48. package/dist/framework-detector.js.map +0 -1
  49. package/dist/git-helpers/git-credential-helper.d.ts +0 -29
  50. package/dist/git-helpers/git-credential-helper.d.ts.map +0 -1
  51. package/dist/git-helpers/git-credential-helper.js +0 -349
  52. package/dist/git-helpers/git-credential-helper.js.map +0 -1
  53. package/dist/index.d.ts.map +0 -1
  54. package/dist/ipc/ipc-client.d.ts +0 -116
  55. package/dist/ipc/ipc-client.d.ts.map +0 -1
  56. package/dist/ipc/ipc-client.js +0 -216
  57. package/dist/ipc/ipc-client.js.map +0 -1
  58. package/dist/ipc/ipc-server.d.ts +0 -55
  59. package/dist/ipc/ipc-server.d.ts.map +0 -1
  60. package/dist/ipc/ipc-server.js +0 -177
  61. package/dist/ipc/ipc-server.js.map +0 -1
  62. package/dist/output.d.ts +0 -48
  63. package/dist/output.d.ts.map +0 -1
  64. package/dist/output.js +0 -129
  65. package/dist/output.js.map +0 -1
  66. package/dist/utils/port-check.d.ts +0 -15
  67. package/dist/utils/port-check.d.ts.map +0 -1
  68. package/dist/utils/port-check.js +0 -79
  69. package/dist/utils/port-check.js.map +0 -1
  70. package/dist/utils/update-checker.d.ts +0 -23
  71. package/dist/utils/update-checker.d.ts.map +0 -1
  72. package/dist/utils/update-checker.js +0 -95
  73. package/dist/utils/update-checker.js.map +0 -1
@@ -1,349 +0,0 @@
1
- "use strict";
2
- /**
3
- * EP548/EP612: Git Credential Helper Script Generator
4
- *
5
- * This module generates the git credential helper script that is installed
6
- * during `episoda auth`. The script is called by git when credentials are needed.
7
- *
8
- * The generated script:
9
- * 1. Detects the environment (local vs cloud)
10
- * 2. Calls GET /api/git/credentials with appropriate auth
11
- * 3. Returns credentials in git credential protocol format
12
- * 4. Caches tokens locally (5 min TTL) to avoid API calls on every git operation
13
- *
14
- * EP612: Removed jq dependency - uses pure bash JSON parsing
15
- */
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.CREDENTIAL_HELPER_SCRIPT = void 0;
18
- exports.generateCredentialHelperScript = generateCredentialHelperScript;
19
- /**
20
- * Generate the credential helper script content
21
- *
22
- * The script needs to:
23
- * - Be standalone (no external dependencies - just bash and curl)
24
- * - Work with curl (available on all platforms)
25
- * - Handle both local (OAuth) and cloud (machine ID) auth
26
- * - Cache tokens to avoid hitting API on every git operation
27
- */
28
- function generateCredentialHelperScript(apiUrl) {
29
- // The script uses bash because it's universally available
30
- // No jq dependency - uses pure bash for JSON parsing
31
- return `#!/bin/bash
32
- #
33
- # Episoda Git Credential Helper
34
- # EP548/EP612: Unified git authentication for all environments
35
- #
36
- # This script is called by git when credentials are needed.
37
- # It calls the Episoda API to get a fresh GitHub token.
38
- #
39
- # Installation: episoda auth
40
- # Location: ~/.episoda/bin/git-credential-episoda (local)
41
- # /usr/local/bin/git-credential-episoda (cloud VM)
42
- #
43
- # Git credential protocol:
44
- # - git calls: git-credential-episoda get
45
- # - input on stdin: protocol=https\\nhost=github.com\\n
46
- # - output on stdout: username=x-access-token\\npassword=TOKEN\\n
47
- #
48
- # Dependencies: bash, curl (no jq required)
49
- #
50
-
51
- set -euo pipefail
52
-
53
- EPISODA_DIR="\${HOME}/.episoda"
54
- CONFIG_FILE="\${EPISODA_DIR}/config.json"
55
- CACHE_FILE="\${EPISODA_DIR}/git-token-cache.json"
56
- API_URL="${apiUrl}"
57
-
58
- # Cache TTL in seconds (5 minutes)
59
- CACHE_TTL=300
60
-
61
- # Log function (to stderr so git doesn't see it)
62
- log() {
63
- if [[ "\${GIT_CREDENTIAL_EPISODA_DEBUG:-}" == "1" ]]; then
64
- echo "[episoda-git] \$(date '+%H:%M:%S') \$*" >&2
65
- fi
66
- }
67
-
68
- # Error log (always shown)
69
- error() {
70
- echo "[episoda-git] ERROR: \$*" >&2
71
- }
72
-
73
- # Pure bash JSON value extraction (no jq needed)
74
- # Usage: json_get '{"foo":"bar"}' "foo" -> "bar"
75
- # Handles simple flat JSON and nested paths like "credentials.username"
76
- json_get() {
77
- local json="\$1"
78
- local key="\$2"
79
- local value=""
80
-
81
- # Handle nested keys (e.g., "credentials.username")
82
- if [[ "\$key" == *.* ]]; then
83
- local outer="\${key%%.*}"
84
- local inner="\${key#*.}"
85
- # Extract outer object first, then inner key
86
- # Match "outer":{...} and extract the {...} part
87
- local nested
88
- nested=\$(echo "\$json" | sed -n 's/.*"'\$outer'"[[:space:]]*:[[:space:]]*{\\([^}]*\\)}.*/\\1/p')
89
- if [[ -n "\$nested" ]]; then
90
- json_get "{\$nested}" "\$inner"
91
- return
92
- fi
93
- return
94
- fi
95
-
96
- # Simple key extraction: "key":"value" or "key": "value"
97
- # Handle both quoted strings and unquoted values
98
- value=\$(echo "\$json" | sed -n 's/.*"'\$key'"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p')
99
-
100
- if [[ -n "\$value" ]]; then
101
- echo "\$value"
102
- fi
103
- }
104
-
105
- # Check for required dependencies
106
- check_dependencies() {
107
- if ! command -v curl >/dev/null 2>&1; then
108
- error "curl is required but not installed"
109
- return 1
110
- fi
111
- return 0
112
- }
113
-
114
- # Parse git credential input from stdin
115
- parse_input() {
116
- while IFS= read -r line; do
117
- [[ -z "\$line" ]] && break
118
- case "\$line" in
119
- protocol=*) PROTOCOL="\${line#protocol=}" ;;
120
- host=*) HOST="\${line#host=}" ;;
121
- path=*) PATH_="\${line#path=}" ;;
122
- esac
123
- done
124
- }
125
-
126
- # Parse ISO 8601 date to unix timestamp (cross-platform)
127
- parse_iso_date() {
128
- local iso_date="\$1"
129
- # Try GNU date first (Linux)
130
- if date -d "\$iso_date" +%s 2>/dev/null; then
131
- return
132
- fi
133
- # Try BSD date (macOS) - strip timezone for parsing
134
- local clean_date="\${iso_date%+*}" # Remove +00:00
135
- clean_date="\${clean_date%Z}" # Remove Z
136
- clean_date="\${clean_date%.*}" # Remove .milliseconds
137
- if date -jf "%Y-%m-%dT%H:%M:%S" "\$clean_date" +%s 2>/dev/null; then
138
- return
139
- fi
140
- # Fallback: return 0 (expired)
141
- echo "0"
142
- }
143
-
144
- # Check if cached token is still valid
145
- get_cached_token() {
146
- if [[ ! -f "\$CACHE_FILE" ]]; then
147
- log "No cache file"
148
- return 1
149
- fi
150
-
151
- # Read cache file
152
- local cache_content
153
- cache_content=\$(cat "\$CACHE_FILE" 2>/dev/null) || return 1
154
-
155
- # Parse cache file using pure bash
156
- local expires_at
157
- expires_at=\$(json_get "\$cache_content" "expires_at")
158
-
159
- if [[ -z "\$expires_at" ]]; then
160
- log "No expires_at in cache"
161
- return 1
162
- fi
163
-
164
- # Check if expired (with 60 second buffer)
165
- local now expires_ts buffer
166
- now=\$(date +%s)
167
- expires_ts=\$(parse_iso_date "\$expires_at")
168
- buffer=60
169
-
170
- if [[ \$((expires_ts - buffer)) -le \$now ]]; then
171
- log "Cache expired (expires: \$expires_at)"
172
- return 1
173
- fi
174
-
175
- # Return cached token
176
- CACHED_TOKEN=\$(json_get "\$cache_content" "password")
177
- CACHED_USER=\$(json_get "\$cache_content" "username")
178
-
179
- if [[ -n "\$CACHED_TOKEN" && -n "\$CACHED_USER" ]]; then
180
- log "Using cached token (expires: \$expires_at)"
181
- return 0
182
- fi
183
-
184
- log "Invalid cache content"
185
- return 1
186
- }
187
-
188
- # Save token to cache
189
- save_to_cache() {
190
- local username="\$1"
191
- local password="\$2"
192
- local expires_at="\$3"
193
-
194
- mkdir -p "\$EPISODA_DIR"
195
- cat > "\$CACHE_FILE" <<CACHE_EOF
196
- {"username":"\$username","password":"\$password","expires_at":"\$expires_at","cached_at":"\$(date -u +"%Y-%m-%dT%H:%M:%SZ")"}
197
- CACHE_EOF
198
- chmod 600 "\$CACHE_FILE"
199
- log "Token cached until \$expires_at"
200
- }
201
-
202
- # Get credentials from Episoda API
203
- fetch_credentials() {
204
- local api_url="\${EPISODA_API_URL:-\${API_URL}}"
205
- local response=""
206
- local http_code=""
207
-
208
- # Detect environment - check multiple ways to identify a cloud VM
209
- local machine_id=""
210
-
211
- # Check FLY_MACHINE_ID (set by Fly.io on all machines)
212
- if [[ -n "\${FLY_MACHINE_ID:-}" ]]; then
213
- machine_id="\$FLY_MACHINE_ID"
214
- log "Cloud environment detected via FLY_MACHINE_ID: \$machine_id"
215
- # Legacy: check /app/.machine_id file
216
- elif [[ -f "/app/.machine_id" ]]; then
217
- machine_id=\$(cat /app/.machine_id)
218
- log "Cloud environment detected via /app/.machine_id: \$machine_id"
219
- fi
220
-
221
- if [[ -n "\$machine_id" ]]; then
222
- # Cloud VM: use machine ID header
223
- log "Fetching credentials for machine: \$machine_id"
224
- response=\$(curl -s -w "\\n%{http_code}" --max-time 10 "\${api_url}/api/git/credentials" \\
225
- -H "X-Machine-ID: \$machine_id" \\
226
- -H "Content-Type: application/json" 2>&1) || {
227
- error "curl failed: \$response"
228
- return 1
229
- }
230
- else
231
- # Local: use OAuth token from config
232
- if [[ ! -f "\$CONFIG_FILE" ]]; then
233
- error "No config found at \$CONFIG_FILE. Run 'episoda auth' first."
234
- return 1
235
- fi
236
-
237
- # Parse config using pure bash
238
- local config_content
239
- config_content=\$(cat "\$CONFIG_FILE" 2>/dev/null) || {
240
- error "Cannot read config file"
241
- return 1
242
- }
243
-
244
- local access_token project_id
245
- access_token=\$(json_get "\$config_content" "access_token")
246
- project_id=\$(json_get "\$config_content" "project_id")
247
-
248
- if [[ -z "\$access_token" ]]; then
249
- error "No access token in config. Run 'episoda auth' to authenticate."
250
- return 1
251
- fi
252
-
253
- log "Local environment (project: \$project_id)"
254
- response=\$(curl -s -w "\\n%{http_code}" --max-time 10 "\${api_url}/api/git/credentials" \\
255
- -H "Authorization: Bearer \$access_token" \\
256
- -H "X-Project-ID: \$project_id" \\
257
- -H "Content-Type: application/json" 2>&1) || {
258
- error "curl failed: \$response"
259
- return 1
260
- }
261
- fi
262
-
263
- # Split response and HTTP code
264
- http_code=\$(echo "\$response" | tail -n1)
265
- response=\$(echo "\$response" | sed '\$d')
266
-
267
- # Check HTTP status
268
- if [[ "\$http_code" != "200" ]]; then
269
- error "API returned HTTP \$http_code"
270
- log "Response: \$response"
271
- return 1
272
- fi
273
-
274
- # Parse response using pure bash
275
- CRED_USERNAME=\$(json_get "\$response" "credentials.username")
276
- CRED_PASSWORD=\$(json_get "\$response" "credentials.password")
277
- CRED_EXPIRES=\$(json_get "\$response" "credentials.expires_at")
278
-
279
- if [[ -z "\$CRED_USERNAME" || -z "\$CRED_PASSWORD" ]]; then
280
- error "Invalid credentials in response"
281
- log "Response: \$response"
282
- return 1
283
- fi
284
-
285
- # Cache the token
286
- save_to_cache "\$CRED_USERNAME" "\$CRED_PASSWORD" "\$CRED_EXPIRES"
287
-
288
- log "Credentials fetched successfully"
289
- return 0
290
- }
291
-
292
- # Main
293
- main() {
294
- local command="\${1:-}"
295
-
296
- # Check dependencies before processing
297
- if ! check_dependencies; then
298
- exit 0 # Exit gracefully so git tries other helpers
299
- fi
300
-
301
- case "\$command" in
302
- get)
303
- parse_input
304
-
305
- # Only handle github.com
306
- if [[ "\${HOST:-}" != "github.com" ]]; then
307
- log "Not handling host: \${HOST:-unknown}"
308
- exit 0
309
- fi
310
-
311
- # Try cache first
312
- if get_cached_token; then
313
- echo "username=\$CACHED_USER"
314
- echo "password=\$CACHED_TOKEN"
315
- exit 0
316
- fi
317
-
318
- # Fetch fresh credentials
319
- if fetch_credentials; then
320
- echo "username=\$CRED_USERNAME"
321
- echo "password=\$CRED_PASSWORD"
322
- exit 0
323
- fi
324
-
325
- # Failed - let git try other credential helpers
326
- log "Failed to get credentials, falling back to other helpers"
327
- exit 0
328
- ;;
329
-
330
- store|erase)
331
- # We don't store or erase credentials
332
- exit 0
333
- ;;
334
-
335
- *)
336
- # Unknown command
337
- exit 0
338
- ;;
339
- esac
340
- }
341
-
342
- main "\$@"
343
- `;
344
- }
345
- /**
346
- * Get the content of the credential helper for embedding in the CLI
347
- */
348
- exports.CREDENTIAL_HELPER_SCRIPT = generateCredentialHelperScript('https://episoda.dev');
349
- //# sourceMappingURL=git-credential-helper.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"git-credential-helper.js","sourceRoot":"","sources":["../../src/git-helpers/git-credential-helper.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;;AAWH,wEA4TC;AArUD;;;;;;;;GAQG;AACH,SAAgB,8BAA8B,CAAC,MAAc;IAC3D,0DAA0D;IAC1D,qDAAqD;IACrD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;WAyBE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+RhB,CAAA;AACD,CAAC;AAED;;GAEG;AACU,QAAA,wBAAwB,GAAG,8BAA8B,CAAC,qBAAqB,CAAC,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;GAIG"}
@@ -1,116 +0,0 @@
1
- /**
2
- * IPC Client - Used by CLI commands
3
- *
4
- * Sends commands to daemon via Unix domain socket.
5
- * Handles request/response communication.
6
- *
7
- * Socket location: ~/.episoda/daemon.sock
8
- */
9
- export interface IPCRequest {
10
- id: string;
11
- command: string;
12
- params?: any;
13
- }
14
- export interface IPCResponse {
15
- id: string;
16
- success: boolean;
17
- data?: any;
18
- error?: string;
19
- }
20
- /**
21
- * Send command to daemon
22
- *
23
- * Connects to daemon socket, sends command, waits for response.
24
- *
25
- * @param command Command name
26
- * @param params Command parameters
27
- * @param timeout Timeout in milliseconds (default: 15000)
28
- * @returns Response data
29
- * @throws Error if daemon not running or command fails
30
- */
31
- export declare function sendCommand(command: string, params?: any, timeout?: number): Promise<any>;
32
- /**
33
- * Check if daemon is reachable via IPC
34
- *
35
- * @returns true if daemon is running and responding
36
- */
37
- export declare function isDaemonReachable(): Promise<boolean>;
38
- /**
39
- * Add project to daemon
40
- *
41
- * EP734: Now blocking - waits for WebSocket connection to complete
42
- *
43
- * @param projectId Supabase project ID
44
- * @param projectPath Absolute path to project
45
- * @returns Connection result with success/error info
46
- */
47
- export declare function addProject(projectId: string, projectPath: string): Promise<{
48
- success: boolean;
49
- connected: boolean;
50
- error?: string;
51
- }>;
52
- /**
53
- * Remove project from daemon
54
- *
55
- * @param projectPath Absolute path to project
56
- */
57
- export declare function removeProject(projectPath: string): Promise<void>;
58
- /**
59
- * Get daemon status
60
- *
61
- * EP738: Added hostname, platform, arch for status command (HTTP server removed)
62
- *
63
- * @returns Status information including connected projects and device info
64
- */
65
- export declare function getStatus(): Promise<{
66
- running: boolean;
67
- machineId: string;
68
- deviceId?: string;
69
- hostname: string;
70
- platform: string;
71
- arch: string;
72
- projects: Array<{
73
- id: string;
74
- path: string;
75
- name: string;
76
- connected: boolean;
77
- }>;
78
- }>;
79
- /**
80
- * Request daemon to connect to a project's WebSocket
81
- *
82
- * @param projectPath Absolute path to project
83
- */
84
- export declare function connectProject(projectPath: string): Promise<void>;
85
- /**
86
- * Request daemon to disconnect from a project's WebSocket
87
- *
88
- * @param projectPath Absolute path to project
89
- */
90
- export declare function disconnectProject(projectPath: string): Promise<void>;
91
- /**
92
- * Request daemon shutdown
93
- */
94
- export declare function shutdownDaemon(): Promise<void>;
95
- /**
96
- * EP805: Verify connection health
97
- *
98
- * Checks if connections are actually healthy (in both connections Map and liveConnections Set).
99
- * Useful for detecting stale connections where WebSocket died but entry persists.
100
- *
101
- * @returns Health status with per-project details
102
- */
103
- export declare function verifyHealth(): Promise<{
104
- totalProjects: number;
105
- healthyConnections: number;
106
- staleConnections: number;
107
- projects: Array<{
108
- id: string;
109
- path: string;
110
- name: string;
111
- inConnectionsMap: boolean;
112
- inLiveConnections: boolean;
113
- isHealthy: boolean;
114
- }>;
115
- }>;
116
- //# sourceMappingURL=ipc-client.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ipc-client.d.ts","sourceRoot":"","sources":["../../src/ipc/ipc-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAUH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,GAAG,CAAA;CACb;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,CAAC,EAAE,GAAG,CAAA;IACV,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,GAAG,EACZ,OAAO,GAAE,MAAwB,GAChC,OAAO,CAAC,GAAG,CAAC,CA2Ed;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO1D;AAED;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;IAChF,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAC,CAGD;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtE;AAED;;;;;;GAMG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC;IACzC,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,KAAK,CAAC;QACd,EAAE,EAAE,MAAM,CAAA;QACV,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAA;QACZ,SAAS,EAAE,OAAO,CAAA;KACnB,CAAC,CAAA;CACH,CAAC,CAED;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEvE;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1E;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAEpD;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC;IAC5C,aAAa,EAAE,MAAM,CAAA;IACrB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,gBAAgB,EAAE,MAAM,CAAA;IACxB,QAAQ,EAAE,KAAK,CAAC;QACd,EAAE,EAAE,MAAM,CAAA;QACV,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAA;QACZ,gBAAgB,EAAE,OAAO,CAAA;QACzB,iBAAiB,EAAE,OAAO,CAAA;QAC1B,SAAS,EAAE,OAAO,CAAA;KACnB,CAAC,CAAA;CACH,CAAC,CAED"}
@@ -1,216 +0,0 @@
1
- "use strict";
2
- /**
3
- * IPC Client - Used by CLI commands
4
- *
5
- * Sends commands to daemon via Unix domain socket.
6
- * Handles request/response communication.
7
- *
8
- * Socket location: ~/.episoda/daemon.sock
9
- */
10
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
- if (k2 === undefined) k2 = k;
12
- var desc = Object.getOwnPropertyDescriptor(m, k);
13
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14
- desc = { enumerable: true, get: function() { return m[k]; } };
15
- }
16
- Object.defineProperty(o, k2, desc);
17
- }) : (function(o, m, k, k2) {
18
- if (k2 === undefined) k2 = k;
19
- o[k2] = m[k];
20
- }));
21
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
22
- Object.defineProperty(o, "default", { enumerable: true, value: v });
23
- }) : function(o, v) {
24
- o["default"] = v;
25
- });
26
- var __importStar = (this && this.__importStar) || (function () {
27
- var ownKeys = function(o) {
28
- ownKeys = Object.getOwnPropertyNames || function (o) {
29
- var ar = [];
30
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
31
- return ar;
32
- };
33
- return ownKeys(o);
34
- };
35
- return function (mod) {
36
- if (mod && mod.__esModule) return mod;
37
- var result = {};
38
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
39
- __setModuleDefault(result, mod);
40
- return result;
41
- };
42
- })();
43
- Object.defineProperty(exports, "__esModule", { value: true });
44
- exports.sendCommand = sendCommand;
45
- exports.isDaemonReachable = isDaemonReachable;
46
- exports.addProject = addProject;
47
- exports.removeProject = removeProject;
48
- exports.getStatus = getStatus;
49
- exports.connectProject = connectProject;
50
- exports.disconnectProject = disconnectProject;
51
- exports.shutdownDaemon = shutdownDaemon;
52
- exports.verifyHealth = verifyHealth;
53
- const net = __importStar(require("net"));
54
- const path = __importStar(require("path"));
55
- const crypto = __importStar(require("crypto"));
56
- const core_1 = require("@episoda/core");
57
- const getSocketPath = () => path.join((0, core_1.getConfigDir)(), 'daemon.sock');
58
- const DEFAULT_TIMEOUT = 15000; // 15 seconds (EP606: increased for device registration)
59
- /**
60
- * Send command to daemon
61
- *
62
- * Connects to daemon socket, sends command, waits for response.
63
- *
64
- * @param command Command name
65
- * @param params Command parameters
66
- * @param timeout Timeout in milliseconds (default: 15000)
67
- * @returns Response data
68
- * @throws Error if daemon not running or command fails
69
- */
70
- async function sendCommand(command, params, timeout = DEFAULT_TIMEOUT) {
71
- return new Promise((resolve, reject) => {
72
- const socket = net.createConnection(getSocketPath());
73
- const requestId = crypto.randomUUID();
74
- let buffer = '';
75
- let timeoutHandle;
76
- // Set timeout
77
- timeoutHandle = setTimeout(() => {
78
- socket.destroy();
79
- reject(new Error(`Command timed out after ${timeout}ms`));
80
- }, timeout);
81
- socket.on('connect', () => {
82
- // Send request
83
- const request = {
84
- id: requestId,
85
- command,
86
- params,
87
- };
88
- socket.write(JSON.stringify(request) + '\n');
89
- });
90
- socket.on('data', (chunk) => {
91
- buffer += chunk.toString();
92
- // Check for complete response (delimited by newline)
93
- const newlineIndex = buffer.indexOf('\n');
94
- if (newlineIndex === -1)
95
- return;
96
- // Extract response
97
- const message = buffer.slice(0, newlineIndex);
98
- try {
99
- const response = JSON.parse(message);
100
- // Verify response ID matches
101
- if (response.id !== requestId) {
102
- reject(new Error('Response ID mismatch'));
103
- return;
104
- }
105
- clearTimeout(timeoutHandle);
106
- socket.end();
107
- if (response.success) {
108
- resolve(response.data);
109
- }
110
- else {
111
- reject(new Error(response.error || 'Command failed'));
112
- }
113
- }
114
- catch (error) {
115
- clearTimeout(timeoutHandle);
116
- socket.end();
117
- reject(new Error('Invalid response from daemon'));
118
- }
119
- });
120
- socket.on('error', (error) => {
121
- clearTimeout(timeoutHandle);
122
- // Check for common errors
123
- if (error.code === 'ENOENT' || error.code === 'ECONNREFUSED') {
124
- reject(new Error('Daemon is not running. Start it with: episoda dev'));
125
- }
126
- else {
127
- reject(error);
128
- }
129
- });
130
- socket.on('timeout', () => {
131
- clearTimeout(timeoutHandle);
132
- socket.destroy();
133
- reject(new Error('Connection timeout'));
134
- });
135
- });
136
- }
137
- /**
138
- * Check if daemon is reachable via IPC
139
- *
140
- * @returns true if daemon is running and responding
141
- */
142
- async function isDaemonReachable() {
143
- try {
144
- await sendCommand('ping', {}, 1000);
145
- return true;
146
- }
147
- catch (error) {
148
- return false;
149
- }
150
- }
151
- /**
152
- * Add project to daemon
153
- *
154
- * EP734: Now blocking - waits for WebSocket connection to complete
155
- *
156
- * @param projectId Supabase project ID
157
- * @param projectPath Absolute path to project
158
- * @returns Connection result with success/error info
159
- */
160
- async function addProject(projectId, projectPath) {
161
- // EP734: Increased timeout to 30s to allow for WebSocket connection
162
- return await sendCommand('add-project', { projectId, projectPath }, 30000);
163
- }
164
- /**
165
- * Remove project from daemon
166
- *
167
- * @param projectPath Absolute path to project
168
- */
169
- async function removeProject(projectPath) {
170
- await sendCommand('remove-project', { projectPath });
171
- }
172
- /**
173
- * Get daemon status
174
- *
175
- * EP738: Added hostname, platform, arch for status command (HTTP server removed)
176
- *
177
- * @returns Status information including connected projects and device info
178
- */
179
- async function getStatus() {
180
- return await sendCommand('status');
181
- }
182
- /**
183
- * Request daemon to connect to a project's WebSocket
184
- *
185
- * @param projectPath Absolute path to project
186
- */
187
- async function connectProject(projectPath) {
188
- await sendCommand('connect-project', { projectPath });
189
- }
190
- /**
191
- * Request daemon to disconnect from a project's WebSocket
192
- *
193
- * @param projectPath Absolute path to project
194
- */
195
- async function disconnectProject(projectPath) {
196
- await sendCommand('disconnect-project', { projectPath });
197
- }
198
- /**
199
- * Request daemon shutdown
200
- */
201
- async function shutdownDaemon() {
202
- await sendCommand('shutdown', {}, 2000);
203
- }
204
- /**
205
- * EP805: Verify connection health
206
- *
207
- * Checks if connections are actually healthy (in both connections Map and liveConnections Set).
208
- * Useful for detecting stale connections where WebSocket died but entry persists.
209
- *
210
- * @returns Health status with per-project details
211
- */
212
- async function verifyHealth() {
213
- return await sendCommand('verify-health');
214
- }
215
- // EP734: Removed getConnectionStatus - no longer needed with blocking add-project
216
- //# sourceMappingURL=ipc-client.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ipc-client.js","sourceRoot":"","sources":["../../src/ipc/ipc-client.ts"],"names":[],"mappings":"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"}