@cluesmith/codev 2.0.0-rc.47 → 2.0.0-rc.48

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.
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Tower API Client (Spec 0090 Phase 3)
3
+ *
4
+ * Provides a client for CLI commands to interact with the tower daemon.
5
+ * Handles local-key authentication and common API operations.
6
+ */
7
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
8
+ import { resolve } from 'node:path';
9
+ import { homedir } from 'node:os';
10
+ import { randomBytes } from 'node:crypto';
11
+ // Tower configuration
12
+ const DEFAULT_TOWER_PORT = 4100;
13
+ const AGENT_FARM_DIR = resolve(homedir(), '.agent-farm');
14
+ const LOCAL_KEY_PATH = resolve(AGENT_FARM_DIR, 'local-key');
15
+ // Request timeout
16
+ const REQUEST_TIMEOUT_MS = 10000;
17
+ /**
18
+ * Get or create the local key for CLI authentication
19
+ */
20
+ function getLocalKey() {
21
+ if (!existsSync(AGENT_FARM_DIR)) {
22
+ mkdirSync(AGENT_FARM_DIR, { recursive: true, mode: 0o700 });
23
+ }
24
+ if (!existsSync(LOCAL_KEY_PATH)) {
25
+ const key = randomBytes(32).toString('hex');
26
+ writeFileSync(LOCAL_KEY_PATH, key, { mode: 0o600 });
27
+ return key;
28
+ }
29
+ return readFileSync(LOCAL_KEY_PATH, 'utf-8').trim();
30
+ }
31
+ /**
32
+ * Encode a project path for use in tower API URLs
33
+ */
34
+ export function encodeProjectPath(projectPath) {
35
+ return Buffer.from(projectPath).toString('base64url');
36
+ }
37
+ /**
38
+ * Decode a project path from tower API URL
39
+ */
40
+ export function decodeProjectPath(encoded) {
41
+ return Buffer.from(encoded, 'base64url').toString('utf-8');
42
+ }
43
+ /**
44
+ * Tower API client class
45
+ */
46
+ export class TowerClient {
47
+ baseUrl;
48
+ localKey;
49
+ constructor(port = DEFAULT_TOWER_PORT) {
50
+ this.baseUrl = `http://localhost:${port}`;
51
+ this.localKey = getLocalKey();
52
+ }
53
+ /**
54
+ * Make a request to the tower API
55
+ */
56
+ async request(path, options = {}) {
57
+ try {
58
+ const response = await fetch(`${this.baseUrl}${path}`, {
59
+ ...options,
60
+ headers: {
61
+ ...options.headers,
62
+ 'codev-web-key': this.localKey,
63
+ 'Content-Type': 'application/json',
64
+ },
65
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
66
+ });
67
+ if (!response.ok) {
68
+ const text = await response.text();
69
+ let error;
70
+ try {
71
+ const json = JSON.parse(text);
72
+ error = json.error || json.message || text;
73
+ }
74
+ catch {
75
+ error = text;
76
+ }
77
+ return { ok: false, status: response.status, error };
78
+ }
79
+ if (response.status === 204) {
80
+ return { ok: true, status: 204 };
81
+ }
82
+ const data = (await response.json());
83
+ return { ok: true, status: response.status, data };
84
+ }
85
+ catch (err) {
86
+ const message = err instanceof Error ? err.message : String(err);
87
+ if (message.includes('ECONNREFUSED')) {
88
+ return { ok: false, status: 0, error: 'Tower not running' };
89
+ }
90
+ if (message.includes('timeout')) {
91
+ return { ok: false, status: 0, error: 'Request timeout' };
92
+ }
93
+ return { ok: false, status: 0, error: message };
94
+ }
95
+ }
96
+ /**
97
+ * Check if tower is running and healthy
98
+ */
99
+ async isRunning() {
100
+ const result = await this.request('/health');
101
+ return result.ok && result.data?.status === 'healthy';
102
+ }
103
+ /**
104
+ * Get tower health status
105
+ */
106
+ async getHealth() {
107
+ const result = await this.request('/health');
108
+ return result.ok ? result.data : null;
109
+ }
110
+ /**
111
+ * List all projects known to tower
112
+ */
113
+ async listProjects() {
114
+ const result = await this.request('/api/projects');
115
+ return result.ok ? result.data.projects : [];
116
+ }
117
+ /**
118
+ * Activate a project (start its dashboard)
119
+ */
120
+ async activateProject(projectPath) {
121
+ const encoded = encodeProjectPath(projectPath);
122
+ const result = await this.request(`/api/projects/${encoded}/activate`, { method: 'POST' });
123
+ if (!result.ok) {
124
+ return { ok: false, error: result.error };
125
+ }
126
+ return {
127
+ ok: result.data?.success ?? true,
128
+ adopted: result.data?.adopted,
129
+ error: result.data?.error,
130
+ };
131
+ }
132
+ /**
133
+ * Deactivate a project (stop its dashboard)
134
+ */
135
+ async deactivateProject(projectPath) {
136
+ const encoded = encodeProjectPath(projectPath);
137
+ const result = await this.request(`/api/projects/${encoded}/deactivate`, { method: 'POST' });
138
+ if (!result.ok) {
139
+ return { ok: false, error: result.error };
140
+ }
141
+ return {
142
+ ok: result.data?.success ?? true,
143
+ stopped: result.data?.stopped,
144
+ error: result.data?.error,
145
+ };
146
+ }
147
+ /**
148
+ * Get status of a specific project
149
+ */
150
+ async getProjectStatus(projectPath) {
151
+ const encoded = encodeProjectPath(projectPath);
152
+ const result = await this.request(`/api/projects/${encoded}/status`);
153
+ return result.ok ? result.data : null;
154
+ }
155
+ /**
156
+ * Create a terminal session
157
+ */
158
+ async createTerminal(options) {
159
+ const result = await this.request('/api/terminals', {
160
+ method: 'POST',
161
+ body: JSON.stringify(options),
162
+ });
163
+ return result.ok ? result.data : null;
164
+ }
165
+ /**
166
+ * List all terminal sessions
167
+ */
168
+ async listTerminals() {
169
+ const result = await this.request('/api/terminals');
170
+ return result.ok ? result.data.terminals : [];
171
+ }
172
+ /**
173
+ * Get terminal info
174
+ */
175
+ async getTerminal(terminalId) {
176
+ const result = await this.request(`/api/terminals/${terminalId}`);
177
+ return result.ok ? result.data : null;
178
+ }
179
+ /**
180
+ * Kill a terminal session
181
+ */
182
+ async killTerminal(terminalId) {
183
+ const result = await this.request(`/api/terminals/${terminalId}`, { method: 'DELETE' });
184
+ return result.ok;
185
+ }
186
+ /**
187
+ * Resize a terminal
188
+ */
189
+ async resizeTerminal(terminalId, cols, rows) {
190
+ const result = await this.request(`/api/terminals/${terminalId}/resize`, {
191
+ method: 'POST',
192
+ body: JSON.stringify({ cols, rows }),
193
+ });
194
+ return result.ok ? result.data : null;
195
+ }
196
+ /**
197
+ * Get the tower dashboard URL for a project
198
+ */
199
+ getProjectUrl(projectPath) {
200
+ const encoded = encodeProjectPath(projectPath);
201
+ return `${this.baseUrl}/project/${encoded}/`;
202
+ }
203
+ /**
204
+ * Get the WebSocket URL for a terminal
205
+ */
206
+ getTerminalWsUrl(terminalId) {
207
+ return `ws://localhost:${new URL(this.baseUrl).port}/ws/terminal/${terminalId}`;
208
+ }
209
+ }
210
+ /**
211
+ * Default tower client instance
212
+ */
213
+ let defaultClient = null;
214
+ /**
215
+ * Get the default tower client
216
+ */
217
+ export function getTowerClient(port) {
218
+ if (!defaultClient || (port && port !== DEFAULT_TOWER_PORT)) {
219
+ defaultClient = new TowerClient(port);
220
+ }
221
+ return defaultClient;
222
+ }
223
+ //# sourceMappingURL=tower-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tower-client.js","sourceRoot":"","sources":["../../../src/agent-farm/lib/tower-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,sBAAsB;AACtB,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAChC,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,EAAE,EAAE,aAAa,CAAC,CAAC;AACzD,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;AAE5D,kBAAkB;AAClB,MAAM,kBAAkB,GAAG,KAAK,CAAC;AAgEjC;;GAEG;AACH,SAAS,WAAW;IAClB,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QAChC,SAAS,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QAChC,MAAM,GAAG,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC5C,aAAa,CAAC,cAAc,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACpD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,OAAO,YAAY,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;AACtD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,WAAmB;IACnD,OAAO,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AACxD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC7D,CAAC;AAED;;GAEG;AACH,MAAM,OAAO,WAAW;IACL,OAAO,CAAS;IAChB,QAAQ,CAAS;IAElC,YAAY,OAAe,kBAAkB;QAC3C,IAAI,CAAC,OAAO,GAAG,oBAAoB,IAAI,EAAE,CAAC;QAC1C,IAAI,CAAC,QAAQ,GAAG,WAAW,EAAE,CAAC;IAChC,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,OAAO,CACnB,IAAY,EACZ,UAAuB,EAAE;QAEzB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE;gBACrD,GAAG,OAAO;gBACV,OAAO,EAAE;oBACP,GAAG,OAAO,CAAC,OAAO;oBAClB,eAAe,EAAE,IAAI,CAAC,QAAQ;oBAC9B,cAAc,EAAE,kBAAkB;iBACnC;gBACD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,kBAAkB,CAAC;aAChD,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnC,IAAI,KAAa,CAAC;gBAClB,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBAC9B,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;gBAC7C,CAAC;gBAAC,MAAM,CAAC;oBACP,KAAK,GAAG,IAAI,CAAC;gBACf,CAAC;gBACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;YACvD,CAAC;YAED,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC5B,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;YACnC,CAAC;YAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAM,CAAC;YAC1C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;QACrD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;gBACrC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC;YAC9D,CAAC;YACD,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;gBAChC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC;YAC5D,CAAC;YACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;QAClD,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,SAAS;QACb,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAc,SAAS,CAAC,CAAC;QAC1D,OAAO,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,CAAC;IACxD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,SAAS;QACb,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAc,SAAS,CAAC,CAAC;QAC1D,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACzC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY;QAChB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAA+B,eAAe,CAAC,CAAC;QACjF,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IAChD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CACnB,WAAmB;QAEnB,MAAM,OAAO,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAC/B,iBAAiB,OAAO,WAAW,EACnC,EAAE,MAAM,EAAE,MAAM,EAAE,CACnB,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;QAC5C,CAAC;QAED,OAAO;YACL,EAAE,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,IAAI,IAAI;YAChC,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO;YAC7B,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK;SAC1B,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB,CACrB,WAAmB;QAEnB,MAAM,OAAO,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAC/B,iBAAiB,OAAO,aAAa,EACrC,EAAE,MAAM,EAAE,MAAM,EAAE,CACnB,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;QAC5C,CAAC;QAED,OAAO;YACL,EAAE,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,IAAI,IAAI;YAChC,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO;YAC7B,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK;SAC1B,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB,CAAC,WAAmB;QACxC,MAAM,OAAO,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAqB,iBAAiB,OAAO,SAAS,CAAC,CAAC;QACzF,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACzC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAAC,OAQpB;QACC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAgB,gBAAgB,EAAE;YACjE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;SAC9B,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACzC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa;QACjB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAiC,gBAAgB,CAAC,CAAC;QACpF,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IACjD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CAAC,UAAkB;QAClC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAgB,kBAAkB,UAAU,EAAE,CAAC,CAAC;QACjF,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACzC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY,CAAC,UAAkB;QACnC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,kBAAkB,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;QACxF,OAAO,MAAM,CAAC,EAAE,CAAC;IACnB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAClB,UAAkB,EAClB,IAAY,EACZ,IAAY;QAEZ,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAgB,kBAAkB,UAAU,SAAS,EAAE;YACtF,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;SACrC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACzC,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,WAAmB;QAC/B,MAAM,OAAO,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAC;QAC/C,OAAO,GAAG,IAAI,CAAC,OAAO,YAAY,OAAO,GAAG,CAAC;IAC/C,CAAC;IAED;;OAEG;IACH,gBAAgB,CAAC,UAAkB;QACjC,OAAO,kBAAkB,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,gBAAgB,UAAU,EAAE,CAAC;IAClF,CAAC;CACF;AAED;;GAEG;AACH,IAAI,aAAa,GAAuB,IAAI,CAAC;AAE7C;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,IAAa;IAC1C,IAAI,CAAC,aAAa,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,kBAAkB,CAAC,EAAE,CAAC;QAC5D,aAAa,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC"}