@ebowwa/codespaces-types 1.1.0 → 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 (67) hide show
  1. package/{dist/compile → compile}/index.js +41 -15
  2. package/compile/index.ts +553 -0
  3. package/compile/resources.js +116 -0
  4. package/compile/resources.ts +157 -0
  5. package/compile/schemas/resources.js +127 -0
  6. package/compile/schemas/resources.ts +144 -0
  7. package/{dist/compile → compile}/terminal-websocket.js +4 -1
  8. package/compile/terminal-websocket.ts +133 -0
  9. package/compile/time.js +30 -0
  10. package/compile/time.ts +32 -0
  11. package/{dist/compile → compile}/user/distributions.js +0 -1
  12. package/{dist/compile/user/distributions.d.ts → compile/user/distributions.ts} +0 -1
  13. package/{dist/compile → compile}/validation.js +23 -17
  14. package/compile/validation.ts +98 -0
  15. package/index.js +21 -0
  16. package/index.ts +5 -0
  17. package/package.json +38 -45
  18. package/runtime/ai.js +505 -0
  19. package/runtime/ai.ts +501 -0
  20. package/runtime/api.js +677 -0
  21. package/runtime/api.ts +857 -0
  22. package/runtime/database.js +94 -0
  23. package/runtime/database.ts +107 -0
  24. package/runtime/env.js +63 -0
  25. package/runtime/env.ts +68 -0
  26. package/{dist/runtime → runtime}/glm.js +7 -4
  27. package/runtime/glm.ts +36 -0
  28. package/runtime/index.js +28 -0
  29. package/{dist/runtime/index.js → runtime/index.ts} +1 -0
  30. package/runtime/ssh.js +47 -0
  31. package/runtime/ssh.ts +58 -0
  32. package/README.md +0 -65
  33. package/dist/compile/index.d.ts +0 -437
  34. package/dist/compile/index.d.ts.map +0 -1
  35. package/dist/compile/resources.d.ts +0 -69
  36. package/dist/compile/resources.d.ts.map +0 -1
  37. package/dist/compile/resources.js +0 -113
  38. package/dist/compile/schemas/resources.d.ts +0 -166
  39. package/dist/compile/schemas/resources.d.ts.map +0 -1
  40. package/dist/compile/schemas/resources.js +0 -123
  41. package/dist/compile/terminal-websocket.d.ts +0 -109
  42. package/dist/compile/terminal-websocket.d.ts.map +0 -1
  43. package/dist/compile/time.d.ts +0 -7
  44. package/dist/compile/time.d.ts.map +0 -1
  45. package/dist/compile/time.js +0 -27
  46. package/dist/compile/user/distributions.d.ts.map +0 -1
  47. package/dist/compile/validation.d.ts +0 -44
  48. package/dist/compile/validation.d.ts.map +0 -1
  49. package/dist/runtime/ai.d.ts +0 -1336
  50. package/dist/runtime/ai.d.ts.map +0 -1
  51. package/dist/runtime/ai.js +0 -416
  52. package/dist/runtime/api.d.ts +0 -1304
  53. package/dist/runtime/api.d.ts.map +0 -1
  54. package/dist/runtime/api.js +0 -673
  55. package/dist/runtime/database.d.ts +0 -376
  56. package/dist/runtime/database.d.ts.map +0 -1
  57. package/dist/runtime/database.js +0 -91
  58. package/dist/runtime/env.d.ts +0 -121
  59. package/dist/runtime/env.d.ts.map +0 -1
  60. package/dist/runtime/env.js +0 -54
  61. package/dist/runtime/glm.d.ts +0 -17
  62. package/dist/runtime/glm.d.ts.map +0 -1
  63. package/dist/runtime/index.d.ts +0 -13
  64. package/dist/runtime/index.d.ts.map +0 -1
  65. package/dist/runtime/ssh.d.ts +0 -111
  66. package/dist/runtime/ssh.d.ts.map +0 -1
  67. package/dist/runtime/ssh.js +0 -44
@@ -1,6 +1,30 @@
1
+ "use strict";
1
2
  /**
2
3
  * Shared type definitions for frontend and server
3
4
  */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
17
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.LoopStatus = exports.VolumeStatus = exports.ActionStatus = exports.EnvironmentStatus = void 0;
21
+ exports.getEnvLocation = getEnvLocation;
22
+ exports.getEnvRegionName = getEnvRegionName;
23
+ exports.getEnvLocationLabel = getEnvLocationLabel;
24
+ // ============================================================================
25
+ // WebSocket Types (shared between terminal and frontend)
26
+ // ============================================================================
27
+ __exportStar(require("./terminal-websocket.js"), exports);
4
28
  // ============================================================================
5
29
  // Application Types
6
30
  // ============================================================================
@@ -20,7 +44,7 @@
20
44
  * - "stopping" → "deleting"
21
45
  * - "initializing" → "creating"
22
46
  */
23
- export var EnvironmentStatus;
47
+ var EnvironmentStatus;
24
48
  (function (EnvironmentStatus) {
25
49
  EnvironmentStatus["Running"] = "running";
26
50
  EnvironmentStatus["Stopped"] = "stopped";
@@ -30,41 +54,41 @@ export var EnvironmentStatus;
30
54
  EnvironmentStatus["Starting"] = "starting";
31
55
  EnvironmentStatus["Stopping"] = "stopping";
32
56
  EnvironmentStatus["Initializing"] = "initializing";
33
- })(EnvironmentStatus || (EnvironmentStatus = {}));
57
+ })(EnvironmentStatus || (exports.EnvironmentStatus = EnvironmentStatus = {}));
34
58
  /**
35
59
  * Action status - used by HetznerAction
36
60
  */
37
- export var ActionStatus;
61
+ var ActionStatus;
38
62
  (function (ActionStatus) {
39
63
  ActionStatus["Running"] = "running";
40
64
  ActionStatus["Success"] = "success";
41
65
  ActionStatus["Error"] = "error";
42
- })(ActionStatus || (ActionStatus = {}));
66
+ })(ActionStatus || (exports.ActionStatus = ActionStatus = {}));
43
67
  /**
44
68
  * Volume status - used by HetznerVolume
45
69
  */
46
- export var VolumeStatus;
70
+ var VolumeStatus;
47
71
  (function (VolumeStatus) {
48
72
  VolumeStatus["Creating"] = "creating";
49
73
  VolumeStatus["Available"] = "available";
50
74
  VolumeStatus["Deleting"] = "deleting";
51
- })(VolumeStatus || (VolumeStatus = {}));
75
+ })(VolumeStatus || (exports.VolumeStatus = VolumeStatus = {}));
52
76
  /**
53
77
  * Ralph Loop status - used by RalphLoop interface
54
78
  */
55
- export var LoopStatus;
79
+ var LoopStatus;
56
80
  (function (LoopStatus) {
57
81
  LoopStatus["Running"] = "running";
58
82
  LoopStatus["Stopped"] = "stopped";
59
83
  LoopStatus["Error"] = "error";
60
84
  LoopStatus["Completed"] = "completed";
61
- })(LoopStatus || (LoopStatus = {}));
85
+ })(LoopStatus || (exports.LoopStatus = LoopStatus = {}));
62
86
  /**
63
87
  * Get the location object from an environment
64
88
  * @param env - The environment object
65
89
  * @returns The location object or null
66
90
  */
67
- export function getEnvLocation(env) {
91
+ function getEnvLocation(env) {
68
92
  if (!env)
69
93
  return null;
70
94
  return env.location || null;
@@ -74,23 +98,25 @@ export function getEnvLocation(env) {
74
98
  * @param env - The environment object
75
99
  * @returns The region name (e.g., "nbg1") or "Unknown"
76
100
  */
77
- export function getEnvRegionName(env) {
101
+ function getEnvRegionName(env) {
102
+ var _a;
78
103
  if (!env)
79
104
  return "Unknown";
80
- return env.location?.name || "Unknown";
105
+ return ((_a = env.location) === null || _a === void 0 ? void 0 : _a.name) || "Unknown";
81
106
  }
82
107
  /**
83
108
  * Get a human-readable location label with city and country
84
109
  * @param env - The environment object
85
110
  * @returns A formatted location string (e.g., "Nuremberg, DE" or "nbg1" as fallback)
86
111
  */
87
- export function getEnvLocationLabel(env) {
112
+ function getEnvLocationLabel(env) {
113
+ var _a, _b, _c;
88
114
  if (!env)
89
115
  return "Unknown";
90
116
  // Show city, country for better UX
91
- if (env.location?.city && env.location?.country) {
92
- return `${env.location.city}, ${env.location.country}`;
117
+ if (((_a = env.location) === null || _a === void 0 ? void 0 : _a.city) && ((_b = env.location) === null || _b === void 0 ? void 0 : _b.country)) {
118
+ return "".concat(env.location.city, ", ").concat(env.location.country);
93
119
  }
94
120
  // Fallback to location name
95
- return env.location?.name || "Unknown";
121
+ return ((_c = env.location) === null || _c === void 0 ? void 0 : _c.name) || "Unknown";
96
122
  }
@@ -0,0 +1,553 @@
1
+ /**
2
+ * Shared type definitions for frontend and server
3
+ */
4
+
5
+ // ============================================================================
6
+ // WebSocket Types (shared between terminal and frontend)
7
+ // ============================================================================
8
+
9
+ export * from "./terminal-websocket.js";
10
+
11
+ // ============================================================================
12
+ // Hetzner API Types (shared between frontend and backend)
13
+ // ============================================================================
14
+
15
+ /**
16
+ * Hetzner server type with pricing information
17
+ */
18
+ export interface HetznerServerType {
19
+ id: number;
20
+ name: string;
21
+ description: string;
22
+ cores: number;
23
+ memory: number;
24
+ disk: number;
25
+ deprecated?: boolean;
26
+ prices: Array<{
27
+ location: string | null | undefined;
28
+ price_hourly: {
29
+ net: string;
30
+ gross: string;
31
+ };
32
+ price_monthly: {
33
+ net: string;
34
+ gross: string;
35
+ };
36
+ }>;
37
+ storage_type: "local" | "network";
38
+ cpu_type: "shared" | "dedicated";
39
+ }
40
+
41
+ /**
42
+ * Hetzner location/datacenter
43
+ */
44
+ export interface HetznerLocation {
45
+ id: number;
46
+ name: string;
47
+ description: string;
48
+ country: string;
49
+ city: string;
50
+ latitude: number;
51
+ longitude: number;
52
+ network_zone: string;
53
+ }
54
+
55
+ /**
56
+ * Hetzner datacenter (specific facility within a location)
57
+ * Previously backend-only, now shared for full object graph preservation
58
+ */
59
+ export interface HetznerDatacenter {
60
+ id: number;
61
+ name: string;
62
+ description: string;
63
+ location: HetznerLocation;
64
+ supported_server_types?: Array<{
65
+ id: number;
66
+ name: string;
67
+ }> | null;
68
+ available_server_types?: Array<{
69
+ id: number;
70
+ name: string;
71
+ }>;
72
+ }
73
+
74
+ // ============================================================================
75
+ // Application Types
76
+ // ============================================================================
77
+
78
+ // ============================================================================
79
+ // Shared Status Enums
80
+ // ============================================================================
81
+
82
+ /**
83
+ * Environment status - used by Environment interface and HetznerServer mapping
84
+ *
85
+ * Hetzner API returns: "running" | "stopped" | "starting" | "stopping" | "initializing"
86
+ * Environment uses subset: "running" | "stopped" | "creating" | "deleting"
87
+ *
88
+ * Mapping:
89
+ * - "running" → "running"
90
+ * - "stopped" → "stopped"
91
+ * - "starting" → "creating"
92
+ * - "stopping" → "deleting"
93
+ * - "initializing" → "creating"
94
+ */
95
+ export enum EnvironmentStatus {
96
+ Running = "running",
97
+ Stopped = "stopped",
98
+ Creating = "creating",
99
+ Deleting = "deleting",
100
+ // Additional Hetzner server statuses (for API compatibility)
101
+ Starting = "starting",
102
+ Stopping = "stopping",
103
+ Initializing = "initializing",
104
+ }
105
+
106
+ /**
107
+ * Action status - used by HetznerAction
108
+ */
109
+ export enum ActionStatus {
110
+ Running = "running",
111
+ Success = "success",
112
+ Error = "error",
113
+ }
114
+
115
+ /**
116
+ * Volume status - used by HetznerVolume
117
+ */
118
+ export enum VolumeStatus {
119
+ Creating = "creating",
120
+ Available = "available",
121
+ Deleting = "deleting",
122
+ }
123
+
124
+ /**
125
+ * Ralph Loop status - used by RalphLoop interface
126
+ */
127
+ export enum LoopStatus {
128
+ Running = "running",
129
+ Stopped = "stopped",
130
+ Error = "error",
131
+ Completed = "completed",
132
+ }
133
+
134
+ /**
135
+ * Active port on a server
136
+ */
137
+ export interface ActivePort {
138
+ port: number;
139
+ protocol: "tcp" | "udp";
140
+ service?: string;
141
+ state: "open" | "closed" | "filtered";
142
+ }
143
+
144
+ // ============================================================================
145
+ // Base Permissions (shared between Environment and EnvironmentMetadata)
146
+ // ============================================================================
147
+
148
+ // TODO:
149
+ // https://tailscale.com/kb/1015/100.x-addresses
150
+ // - type for every tailnet device has local access to a private service IP address called Quad100 (100.100.100.100)
151
+ // - `Tailscale automatically assigns a unique IP address to each device in your Tailscale network`
152
+ /**
153
+ * Base permissions structure shared by Environment and EnvironmentMetadata
154
+ */
155
+ export interface BasePermissions {
156
+ // Seed/clone configuration
157
+ seedConfig?: {
158
+ sourceEnvironmentId?: string;
159
+ dependencySnapshot?: string;
160
+ setupScript?: string;
161
+ };
162
+
163
+ // Authentication providers
164
+ logins?: {
165
+ github?: {
166
+ enabled: boolean;
167
+ username?: string;
168
+ tokenScopes?: string[];
169
+ };
170
+ doppler?: {
171
+ enabled: boolean;
172
+ project?: string;
173
+ config?: string;
174
+ };
175
+ tailscale?: {
176
+ enabled: boolean;
177
+ authKey?: string;
178
+ hostname?: string;
179
+ };
180
+ };
181
+
182
+ // VPN configurations
183
+ vpns?: Array<{
184
+ name: string;
185
+ type: "wireguard" | "openvpn" | "tailscale";
186
+ config: string;
187
+ connected: boolean;
188
+ }>;
189
+
190
+ // Generic plugin configuration
191
+ plugins?: Record<string, ClaudeCodePlugin>;
192
+ }
193
+
194
+ // ============================================================================
195
+ // Environment Base (shared fields between Environment and EnvironmentMetadata)
196
+ // ============================================================================
197
+
198
+ /**
199
+ * Base fields shared by Environment and EnvironmentMetadata
200
+ */
201
+ export interface EnvironmentBase {
202
+ id: string;
203
+ description?: string;
204
+ project?: string;
205
+ owner?: string;
206
+ purpose?: string;
207
+ environmentType?: "development" | "staging" | "production" | "testing";
208
+ hoursActive?: number;
209
+ lastActive?: string;
210
+ activePorts?: ActivePort[];
211
+ /** Cloud-init bootstrap status */
212
+ bootstrapStatus?: "bootstrapping" | "ready" | "failed";
213
+ }
214
+
215
+ // TODO: https://code.claude.com/docs/en/common-workflows
216
+
217
+ /**
218
+ * Claude Code hook event types
219
+ */
220
+ export type HookEventType =
221
+ | "SessionStart"
222
+ | "UserPromptSubmit"
223
+ | "PreToolUse"
224
+ | "PostToolUse"
225
+ | "PreCommand"
226
+ | "PostCommand"
227
+ | "Stop"
228
+ | "Error"
229
+ | "FileChange";
230
+
231
+ /**
232
+ * Claude Code hook configuration
233
+ */
234
+ export interface ClaudeCodeHook {
235
+ event: HookEventType;
236
+ description?: string;
237
+ command?: string;
238
+ output?: {
239
+ allow?: boolean;
240
+ context?: string;
241
+ modifyInput?: string;
242
+ };
243
+ }
244
+
245
+ /**
246
+ * Claude Code agent configuration
247
+ */
248
+ export interface ClaudeCodeAgent {
249
+ name: string;
250
+ description?: string;
251
+ instructions?: string;
252
+ model?: string;
253
+ temperature?: number;
254
+ maxTokens?: number;
255
+ }
256
+
257
+ /**
258
+ * Claude Code command configuration
259
+ */
260
+ export interface ClaudeCodeCommand {
261
+ name: string;
262
+ description?: string;
263
+ instructions?: string;
264
+ agent?: string;
265
+ shouldConfirm?: boolean;
266
+ parameters?: Record<
267
+ string,
268
+ {
269
+ type: "string" | "boolean" | "number" | "array";
270
+ description?: string;
271
+ required?: boolean;
272
+ default?: unknown;
273
+ }
274
+ >;
275
+ }
276
+
277
+ /**
278
+ * Claude Code skill configuration
279
+ */
280
+ export interface ClaudeCodeSkill {
281
+ name: string;
282
+ description?: string;
283
+ instructions?: string;
284
+ trigger?: {
285
+ patterns?: string[];
286
+ fileTypes?: string[];
287
+ always?: boolean;
288
+ };
289
+ }
290
+
291
+ /**
292
+ * MCP (Model Context Protocol) Server Configuration
293
+ *
294
+ * === LAYER 2: CLI Wrapper Plugin System ===
295
+ *
296
+ * MCP is NOT part of the OpenAI protocol (Layer 1).
297
+ * It's a separate plugin system for exposing tools/resources to AI models.
298
+ *
299
+ * These types are defined but NOT yet implemented in cheapspaces.
300
+ *
301
+ * Reference Implementation: tools/continue/core/context/mcp/
302
+ *
303
+ * Potential MCP Tools for Cheapspaces:
304
+ * - hetzner_create: Create new server (wrap HetznerClient.createServer())
305
+ * - hetzner_delete: Delete server (wrap HetznerClient.deleteServer())
306
+ * - hetzner_power: Power on/off (wrap powerOn/powerOff)
307
+ * - ssh_exec: Execute remote command (wrap execSSH())
308
+ * - ssh_upload: Upload file via SCP (wrap scpUpload())
309
+ * - ssh_download: Download file via SCP (wrap scpDownload())
310
+ * - resources_get: Get resource usage (wrap getResources())
311
+ *
312
+ * To implement (Layer 2 only):
313
+ * 1. Create MCPManagerSingleton (see continue's pattern)
314
+ * 2. Create MCPConnection wrapper for stdio/HTTP servers
315
+ * 3. Expose Hetzner/SSH operations as MCP tools
316
+ * 4. Integrate with AI chat for tool calling
317
+ */
318
+ export interface MCPServerConfig {
319
+ name: string;
320
+ command: string; // For stdio-based servers
321
+ args?: string[];
322
+ env?: Record<string, string>;
323
+ cwd?: string;
324
+ }
325
+
326
+ /**
327
+ * Claude Code plugin configuration
328
+ */
329
+ export interface ClaudeCodePlugin {
330
+ enabled: boolean;
331
+ name?: string;
332
+ description?: string;
333
+ version?: string;
334
+ author?: string;
335
+ commands?: ClaudeCodeCommand[];
336
+ agents?: ClaudeCodeAgent[];
337
+ skills?: ClaudeCodeSkill[];
338
+ hooks?: ClaudeCodeHook[];
339
+ mcpServers?: MCPServerConfig[];
340
+ config?: Record<string, unknown>;
341
+ }
342
+
343
+ /**
344
+ * Server image information
345
+ */
346
+ export interface ServerImage {
347
+ id: number;
348
+ name: string;
349
+ description: string;
350
+ type: "snapshot" | "backup" | "system";
351
+ }
352
+
353
+ /**
354
+ * Environment data - shared between frontend and server
355
+ */
356
+ export interface Environment extends EnvironmentBase {
357
+ // Core identification (id, description from base)
358
+ name: string;
359
+ status:
360
+ | EnvironmentStatus.Running
361
+ | EnvironmentStatus.Stopped
362
+ | EnvironmentStatus.Creating
363
+ | EnvironmentStatus.Deleting;
364
+
365
+ // Action progress (0-100) for long-running operations
366
+ progress?: number;
367
+
368
+ // Server configuration
369
+ serverId: number;
370
+ serverType: string;
371
+ image: ServerImage;
372
+ location?: HetznerLocation;
373
+ datacenter?: HetznerDatacenter;
374
+
375
+ // Network addresses
376
+ ipv4: string | null;
377
+ ipv6: string | null;
378
+
379
+ // Metadata
380
+ createdAt: string;
381
+ lastUsed: string | null;
382
+ tags: string[];
383
+
384
+ // Resource usage metrics
385
+ resources?: {
386
+ cpuPercent: number;
387
+ memoryPercent: number;
388
+ memoryUsed: string;
389
+ memoryTotal: string;
390
+ diskPercent: number;
391
+ diskUsed: string;
392
+ diskTotal: string;
393
+ gpuPercent?: number;
394
+ gpuMemoryUsed?: string;
395
+ gpuMemoryTotal?: string;
396
+ lastUpdated?: string;
397
+ };
398
+
399
+ // Permissions and integrations
400
+ nodeAgent?: NodeAgentInfo;
401
+
402
+ permissions?: BasePermissions & {
403
+ // Available skills (Environment-specific)
404
+ skills?: Array<{
405
+ name: string;
406
+ enabled: boolean;
407
+ config?: Record<string, unknown>;
408
+ }>;
409
+ };
410
+ }
411
+
412
+ /**
413
+ * Get the location object from an environment
414
+ * @param env - The environment object
415
+ * @returns The location object or null
416
+ */
417
+ export function getEnvLocation(
418
+ env: Environment | undefined | null,
419
+ ): HetznerLocation | null {
420
+ if (!env) return null;
421
+ return env.location || null;
422
+ }
423
+
424
+ /**
425
+ * Get the region name (short format like "nbg1") from an environment
426
+ * @param env - The environment object
427
+ * @returns The region name (e.g., "nbg1") or "Unknown"
428
+ */
429
+ export function getEnvRegionName(env: Environment | undefined | null): string {
430
+ if (!env) return "Unknown";
431
+ return env.location?.name || "Unknown";
432
+ }
433
+
434
+ /**
435
+ * Get a human-readable location label with city and country
436
+ * @param env - The environment object
437
+ * @returns A formatted location string (e.g., "Nuremberg, DE" or "nbg1" as fallback)
438
+ */
439
+ export function getEnvLocationLabel(
440
+ env: Environment | undefined | null,
441
+ ): string {
442
+ if (!env) return "Unknown";
443
+ // Show city, country for better UX
444
+ if (env.location?.city && env.location?.country) {
445
+ return `${env.location.city}, ${env.location.country}`;
446
+ }
447
+ // Fallback to location name
448
+ return env.location?.name || "Unknown";
449
+ }
450
+
451
+ /**
452
+ * Environment metadata for storage
453
+ * Extends EnvironmentBase with storage-specific fields
454
+ */
455
+ export interface EnvironmentMetadata extends EnvironmentBase {
456
+ sshKeyPath?: string;
457
+ permissions?: BasePermissions;
458
+ updatedAt?: string;
459
+ }
460
+
461
+ /**
462
+ * Node Agent - Ralph Loop orchestration service running on each VPS
463
+ */
464
+
465
+ /**
466
+ * Git worktree information
467
+ */
468
+ export interface Worktree {
469
+ id: string;
470
+ branch: string;
471
+ commit: string;
472
+ path: string;
473
+ created?: string;
474
+ }
475
+
476
+ /**
477
+ * Ralph Loop status and progress
478
+ */
479
+ export interface RalphLoop {
480
+ id: string;
481
+ worktree_id: string;
482
+ iteration: number;
483
+ max_iterations: number;
484
+ status: LoopStatus;
485
+ started_at: string;
486
+ last_activity?: string;
487
+ recent_commits?: Array<{ hash: string; message: string }>;
488
+ prompt?: string;
489
+ completion_promise?: string | null;
490
+ project_path?: string; // Relative path like ~/seed or ~/seed/worktrees/feature-x
491
+ git_info?: {
492
+ remote: string | null; // e.g., "ebowwa/seed" or null
493
+ branch: string | null; // e.g., "Bun-port" or null
494
+ };
495
+ // Ralph Iterative specific fields
496
+ phase?: "planning" | "executing" | "review" | "complete";
497
+ current_task?: string | null;
498
+ total_subtasks?: number;
499
+ completed_subtasks?: number;
500
+ subtasks?: Array<{
501
+ id: string;
502
+ title: string;
503
+ status: "pending" | "in_progress" | "completed";
504
+ }>;
505
+ }
506
+
507
+ /**
508
+ * Node Agent capacity metrics (system resources)
509
+ */
510
+ export interface NodeCapacity {
511
+ cpu_percent: number;
512
+ memory_percent: number;
513
+ disk_percent: number;
514
+ claude_cpu_total?: number; // Total CPU % used by all Claude processes
515
+ claude_process_count?: number; // Number of active Claude processes
516
+ }
517
+
518
+ /**
519
+ * Active Claude Code process info
520
+ */
521
+ export interface ClaudeCodeProcess {
522
+ pid: number;
523
+ worktreeId?: string;
524
+ loopId?: string;
525
+ startTime: string; // ISO date string
526
+ command: string;
527
+ cpuPercent: number;
528
+ memoryPercent: number;
529
+ }
530
+
531
+ /**
532
+ * Node Agent status response
533
+ */
534
+ export interface NodeAgentStatus {
535
+ node_id: string;
536
+ hostname: string;
537
+ tailscale_ip: string;
538
+ capacity: NodeCapacity;
539
+ worktrees: Worktree[];
540
+ ralph_loops: RalphLoop[];
541
+ active_claude_processes?: ClaudeCodeProcess[];
542
+ }
543
+
544
+ /**
545
+ * Node Agent connection info for UI display
546
+ */
547
+ export interface NodeAgentInfo {
548
+ running: boolean;
549
+ port?: number;
550
+ status?: NodeAgentStatus;
551
+ lastChecked?: string;
552
+ error?: string;
553
+ }