@cluesmith/codev 2.0.0-rc.60 → 2.0.0-rc.63

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 (156) hide show
  1. package/dashboard/dist/assets/index-C7FtNK6Y.css +32 -0
  2. package/dashboard/dist/assets/index-D6VqWAaI.js +131 -0
  3. package/dashboard/dist/assets/index-D6VqWAaI.js.map +1 -0
  4. package/dashboard/dist/index.html +2 -2
  5. package/dist/agent-farm/cli.d.ts.map +1 -1
  6. package/dist/agent-farm/cli.js +75 -50
  7. package/dist/agent-farm/cli.js.map +1 -1
  8. package/dist/agent-farm/commands/architect.d.ts.map +1 -1
  9. package/dist/agent-farm/commands/architect.js +38 -48
  10. package/dist/agent-farm/commands/architect.js.map +1 -1
  11. package/dist/agent-farm/commands/attach.d.ts.map +1 -1
  12. package/dist/agent-farm/commands/attach.js +14 -35
  13. package/dist/agent-farm/commands/attach.js.map +1 -1
  14. package/dist/agent-farm/commands/cleanup.d.ts.map +1 -1
  15. package/dist/agent-farm/commands/cleanup.js +17 -18
  16. package/dist/agent-farm/commands/cleanup.js.map +1 -1
  17. package/dist/agent-farm/commands/consult.d.ts +3 -4
  18. package/dist/agent-farm/commands/consult.d.ts.map +1 -1
  19. package/dist/agent-farm/commands/consult.js +27 -37
  20. package/dist/agent-farm/commands/consult.js.map +1 -1
  21. package/dist/agent-farm/commands/open.d.ts.map +1 -1
  22. package/dist/agent-farm/commands/open.js +19 -36
  23. package/dist/agent-farm/commands/open.js.map +1 -1
  24. package/dist/agent-farm/commands/shell.d.ts +3 -3
  25. package/dist/agent-farm/commands/shell.d.ts.map +1 -1
  26. package/dist/agent-farm/commands/shell.js +33 -78
  27. package/dist/agent-farm/commands/shell.js.map +1 -1
  28. package/dist/agent-farm/commands/spawn.d.ts.map +1 -1
  29. package/dist/agent-farm/commands/spawn.js +113 -90
  30. package/dist/agent-farm/commands/spawn.js.map +1 -1
  31. package/dist/agent-farm/commands/start.d.ts +7 -20
  32. package/dist/agent-farm/commands/start.d.ts.map +1 -1
  33. package/dist/agent-farm/commands/start.js +7 -243
  34. package/dist/agent-farm/commands/start.js.map +1 -1
  35. package/dist/agent-farm/commands/status.d.ts.map +1 -1
  36. package/dist/agent-farm/commands/status.js +22 -29
  37. package/dist/agent-farm/commands/status.js.map +1 -1
  38. package/dist/agent-farm/commands/stop.d.ts.map +1 -1
  39. package/dist/agent-farm/commands/stop.js +43 -172
  40. package/dist/agent-farm/commands/stop.js.map +1 -1
  41. package/dist/agent-farm/commands/tower-cloud.d.ts +47 -0
  42. package/dist/agent-farm/commands/tower-cloud.d.ts.map +1 -0
  43. package/dist/agent-farm/commands/tower-cloud.js +316 -0
  44. package/dist/agent-farm/commands/tower-cloud.js.map +1 -0
  45. package/dist/agent-farm/db/index.d.ts +6 -2
  46. package/dist/agent-farm/db/index.d.ts.map +1 -1
  47. package/dist/agent-farm/db/index.js +56 -31
  48. package/dist/agent-farm/db/index.js.map +1 -1
  49. package/dist/agent-farm/db/migrate.d.ts +0 -4
  50. package/dist/agent-farm/db/migrate.d.ts.map +1 -1
  51. package/dist/agent-farm/db/migrate.js +0 -46
  52. package/dist/agent-farm/db/migrate.js.map +1 -1
  53. package/dist/agent-farm/db/schema.d.ts +3 -3
  54. package/dist/agent-farm/db/schema.d.ts.map +1 -1
  55. package/dist/agent-farm/db/schema.js +3 -17
  56. package/dist/agent-farm/db/schema.js.map +1 -1
  57. package/dist/agent-farm/db/types.d.ts +0 -10
  58. package/dist/agent-farm/db/types.d.ts.map +1 -1
  59. package/dist/agent-farm/db/types.js +0 -8
  60. package/dist/agent-farm/db/types.js.map +1 -1
  61. package/dist/agent-farm/hq-connector.d.ts +1 -1
  62. package/dist/agent-farm/hq-connector.js +1 -1
  63. package/dist/agent-farm/lib/cloud-config.d.ts +46 -0
  64. package/dist/agent-farm/lib/cloud-config.d.ts.map +1 -0
  65. package/dist/agent-farm/lib/cloud-config.js +106 -0
  66. package/dist/agent-farm/lib/cloud-config.js.map +1 -0
  67. package/dist/agent-farm/lib/tower-client.d.ts +7 -5
  68. package/dist/agent-farm/lib/tower-client.d.ts.map +1 -1
  69. package/dist/agent-farm/lib/tower-client.js.map +1 -1
  70. package/dist/agent-farm/lib/tunnel-client.d.ts +117 -0
  71. package/dist/agent-farm/lib/tunnel-client.d.ts.map +1 -0
  72. package/dist/agent-farm/lib/tunnel-client.js +502 -0
  73. package/dist/agent-farm/lib/tunnel-client.js.map +1 -0
  74. package/dist/agent-farm/servers/tower-server.js +865 -441
  75. package/dist/agent-farm/servers/tower-server.js.map +1 -1
  76. package/dist/agent-farm/state.d.ts +2 -2
  77. package/dist/agent-farm/state.d.ts.map +1 -1
  78. package/dist/agent-farm/state.js +6 -16
  79. package/dist/agent-farm/state.js.map +1 -1
  80. package/dist/agent-farm/types.d.ts +1 -18
  81. package/dist/agent-farm/types.d.ts.map +1 -1
  82. package/dist/agent-farm/utils/config.d.ts +0 -5
  83. package/dist/agent-farm/utils/config.d.ts.map +1 -1
  84. package/dist/agent-farm/utils/config.js +0 -31
  85. package/dist/agent-farm/utils/config.js.map +1 -1
  86. package/dist/agent-farm/utils/file-tabs.d.ts +27 -0
  87. package/dist/agent-farm/utils/file-tabs.d.ts.map +1 -0
  88. package/dist/agent-farm/utils/file-tabs.js +46 -0
  89. package/dist/agent-farm/utils/file-tabs.js.map +1 -0
  90. package/dist/agent-farm/utils/gate-status.d.ts +16 -0
  91. package/dist/agent-farm/utils/gate-status.d.ts.map +1 -0
  92. package/dist/agent-farm/utils/gate-status.js +79 -0
  93. package/dist/agent-farm/utils/gate-status.js.map +1 -0
  94. package/dist/agent-farm/utils/gate-watcher.d.ts +38 -0
  95. package/dist/agent-farm/utils/gate-watcher.d.ts.map +1 -0
  96. package/dist/agent-farm/utils/gate-watcher.js +122 -0
  97. package/dist/agent-farm/utils/gate-watcher.js.map +1 -0
  98. package/dist/agent-farm/utils/index.d.ts +0 -1
  99. package/dist/agent-farm/utils/index.d.ts.map +1 -1
  100. package/dist/agent-farm/utils/index.js +0 -1
  101. package/dist/agent-farm/utils/index.js.map +1 -1
  102. package/dist/agent-farm/utils/notifications.js +1 -1
  103. package/dist/agent-farm/utils/notifications.js.map +1 -1
  104. package/dist/agent-farm/utils/server-utils.d.ts +1 -1
  105. package/dist/agent-farm/utils/server-utils.js +1 -1
  106. package/dist/agent-farm/utils/session.d.ts +10 -0
  107. package/dist/agent-farm/utils/session.d.ts.map +1 -0
  108. package/dist/agent-farm/utils/session.js +12 -0
  109. package/dist/agent-farm/utils/session.js.map +1 -0
  110. package/dist/cli.d.ts.map +1 -1
  111. package/dist/cli.js +2 -0
  112. package/dist/cli.js.map +1 -1
  113. package/dist/commands/adopt.js +1 -1
  114. package/dist/commands/adopt.js.map +1 -1
  115. package/dist/commands/consult/index.d.ts +1 -0
  116. package/dist/commands/consult/index.d.ts.map +1 -1
  117. package/dist/commands/consult/index.js +42 -15
  118. package/dist/commands/consult/index.js.map +1 -1
  119. package/dist/commands/init.js +1 -1
  120. package/dist/commands/init.js.map +1 -1
  121. package/dist/commands/porch/index.d.ts.map +1 -1
  122. package/dist/commands/porch/index.js +35 -12
  123. package/dist/commands/porch/index.js.map +1 -1
  124. package/dist/commands/porch/next.js +15 -5
  125. package/dist/commands/porch/next.js.map +1 -1
  126. package/dist/commands/porch/verdict.d.ts +8 -0
  127. package/dist/commands/porch/verdict.d.ts.map +1 -1
  128. package/dist/commands/porch/verdict.js +13 -0
  129. package/dist/commands/porch/verdict.js.map +1 -1
  130. package/dist/terminal/pty-session.d.ts +2 -0
  131. package/dist/terminal/pty-session.d.ts.map +1 -1
  132. package/dist/terminal/pty-session.js +4 -0
  133. package/dist/terminal/pty-session.js.map +1 -1
  134. package/package.json +1 -1
  135. package/skeleton/.claude/skills/af/SKILL.md +15 -0
  136. package/skeleton/consult-types/impl-review.md +9 -0
  137. package/skeleton/protocols/spir/prompts/review.md +15 -16
  138. package/skeleton/protocols/spir/protocol.json +4 -0
  139. package/skeleton/protocols/spir/templates/review.md +81 -199
  140. package/skeleton/resources/commands/agent-farm.md +38 -2
  141. package/templates/tower.html +7 -150
  142. package/dashboard/dist/assets/index-CXloFYpB.css +0 -32
  143. package/dashboard/dist/assets/index-Ca2fjOJf.js +0 -131
  144. package/dashboard/dist/assets/index-Ca2fjOJf.js.map +0 -1
  145. package/dist/agent-farm/utils/orphan-handler.d.ts +0 -27
  146. package/dist/agent-farm/utils/orphan-handler.d.ts.map +0 -1
  147. package/dist/agent-farm/utils/orphan-handler.js +0 -149
  148. package/dist/agent-farm/utils/orphan-handler.js.map +0 -1
  149. package/dist/agent-farm/utils/port-registry.d.ts +0 -57
  150. package/dist/agent-farm/utils/port-registry.d.ts.map +0 -1
  151. package/dist/agent-farm/utils/port-registry.js +0 -166
  152. package/dist/agent-farm/utils/port-registry.js.map +0 -1
  153. package/dist/agent-farm/utils/terminal-ports.d.ts +0 -18
  154. package/dist/agent-farm/utils/terminal-ports.d.ts.map +0 -1
  155. package/dist/agent-farm/utils/terminal-ports.js +0 -35
  156. package/dist/agent-farm/utils/terminal-ports.js.map +0 -1
@@ -8,7 +8,6 @@ import { execFile } from 'node:child_process';
8
8
  import { promisify } from 'node:util';
9
9
  import { loadState, clearState } from '../state.js';
10
10
  import { logger } from '../utils/logger.js';
11
- import { killProcess, killProcessTree, isProcessRunning, run } from '../utils/shell.js';
12
11
  import { getConfig } from '../utils/config.js';
13
12
  import { TowerClient } from '../lib/tower-client.js';
14
13
  const execFileAsync = promisify(execFile);
@@ -16,79 +15,10 @@ const execFileAsync = promisify(execFile);
16
15
  * Default tower port
17
16
  */
18
17
  const DEFAULT_TOWER_PORT = 4100;
19
- /** Kill a tmux session by name. Uses execFile (no shell) to avoid injection.
20
- * If expectedPid is provided, verifies the session's PID matches before killing
21
- * to prevent cross-project kills when two projects share the same basename.
22
- */
23
- async function killTmuxSession(sessionName, expectedPid) {
24
- if (expectedPid && expectedPid > 0) {
25
- // Verify the session belongs to this project by checking its PID
26
- try {
27
- const { stdout } = await execFileAsync('tmux', [
28
- 'list-sessions', '-F', '#{session_name} #{session_pid}',
29
- ]);
30
- const line = stdout.trim().split('\n').find(l => l.startsWith(sessionName + ' '));
31
- if (line) {
32
- const sessionPid = parseInt(line.split(' ')[1], 10);
33
- if (sessionPid !== expectedPid && !isNaN(sessionPid)) {
34
- // PID mismatch — this session belongs to a different project
35
- throw new Error(`Session ${sessionName} PID ${sessionPid} != expected ${expectedPid}`);
36
- }
37
- }
38
- }
39
- catch (err) {
40
- if (err.message?.includes('PID'))
41
- throw err;
42
- // tmux command failed — fall through to kill attempt
43
- }
44
- }
18
+ /** Kill a tmux session by name. Uses execFile (no shell) to avoid injection. */
19
+ async function killTmuxSession(sessionName) {
45
20
  await execFileAsync('tmux', ['kill-session', '-t', sessionName]);
46
21
  }
47
- /**
48
- * Find orphan agent-farm processes for this project that aren't in state
49
- * Returns PIDs of orphaned processes
50
- */
51
- async function findOrphanProcesses(trackedPids) {
52
- const config = getConfig();
53
- const projectRoot = config.projectRoot;
54
- // Pattern to match agent-farm server processes for this project
55
- // Matches: node .../dist/agent-farm/servers/dashboard-server.js
56
- // node .../dist/agent-farm/servers/tower-server.js
57
- // Note: open-server.js removed in Spec 0092 - files served through Tower
58
- const orphans = [];
59
- try {
60
- // Use ps to find node processes, then filter by our project path
61
- const result = await run('ps -eo pid,command');
62
- const lines = result.stdout.split('\n');
63
- for (const line of lines) {
64
- // Skip tower-server entirely - it's a global service, not per-project
65
- if (line.includes('tower-server')) {
66
- continue;
67
- }
68
- // Only match processes that belong to THIS project
69
- // Must contain projectRoot to be considered for orphan cleanup
70
- const isProjectProcess = line.includes(projectRoot) && line.includes('agent-farm');
71
- if (!isProjectProcess) {
72
- continue;
73
- }
74
- // Extract PID (first number in the line)
75
- const match = line.trim().match(/^(\d+)/);
76
- if (!match)
77
- continue;
78
- const pid = parseInt(match[1], 10);
79
- // Skip if this PID is tracked in state
80
- if (trackedPids.has(pid)) {
81
- continue;
82
- }
83
- // This is an orphan
84
- orphans.push(pid);
85
- }
86
- }
87
- catch {
88
- // ps command failed - ignore
89
- }
90
- return orphans;
91
- }
92
22
  /**
93
23
  * Stop all agent farm processes
94
24
  *
@@ -123,126 +53,67 @@ export async function stop() {
123
53
  // Legacy cleanup for processes not managed by tower
124
54
  const state = loadState();
125
55
  let stopped = 0;
126
- // Collect all tracked PIDs for orphan detection
127
- const trackedPids = new Set();
128
- if (state.architect)
129
- trackedPids.add(state.architect.pid);
130
- for (const builder of state.builders)
131
- trackedPids.add(builder.pid);
132
- for (const util of state.utils)
133
- trackedPids.add(util.pid);
134
- for (const annotation of state.annotations)
135
- trackedPids.add(annotation.pid);
136
- // Stop architect — kill tmux session by name (safer than tree-kill)
137
- if (state.architect) {
138
- logger.info(`Stopping architect (PID: ${state.architect.pid})`);
56
+ // Stop architect kill tmux session by name, then Tower terminal
57
+ if (state.architect?.tmuxSession) {
58
+ logger.info('Stopping architect...');
139
59
  try {
140
- // Kill tmux session by name — this cleanly terminates the session and its processes
141
- if (state.architect.tmuxSession) {
142
- try {
143
- await killTmuxSession(state.architect.tmuxSession, state.architect.pid);
144
- stopped++;
145
- }
146
- catch {
147
- // Session may already be gone, try PID fallback
148
- if (await isProcessRunning(state.architect.pid)) {
149
- await killProcess(state.architect.pid);
150
- stopped++;
151
- }
152
- }
153
- }
154
- else if (await isProcessRunning(state.architect.pid)) {
155
- await killProcess(state.architect.pid);
156
- stopped++;
157
- }
60
+ await killTmuxSession(state.architect.tmuxSession);
61
+ stopped++;
158
62
  }
159
- catch (error) {
160
- logger.warn(`Failed to stop architect: ${error}`);
63
+ catch {
64
+ // Session may already be gone
161
65
  }
162
66
  }
163
- // Stop all builders — prefer tmux kill-session over PID kill
164
- for (const builder of state.builders) {
165
- logger.info(`Stopping builder ${builder.id} (PID: ${builder.pid})`);
67
+ if (towerRunning && state.architect?.terminalId) {
166
68
  try {
167
- if (builder.tmuxSession) {
168
- try {
169
- await killTmuxSession(builder.tmuxSession, builder.pid);
170
- stopped++;
171
- }
172
- catch {
173
- if (await isProcessRunning(builder.pid)) {
174
- await killProcess(builder.pid);
175
- stopped++;
176
- }
177
- }
178
- }
179
- else if (await isProcessRunning(builder.pid)) {
180
- await killProcess(builder.pid);
181
- stopped++;
182
- }
183
- }
184
- catch (error) {
185
- logger.warn(`Failed to stop builder ${builder.id}: ${error}`);
69
+ await client.killTerminal(state.architect.terminalId);
186
70
  }
71
+ catch { /* best-effort */ }
187
72
  }
188
- // Stop all utilsprefer tmux kill-session over PID kill
189
- for (const util of state.utils) {
190
- logger.info(`Stopping util ${util.id} (PID: ${util.pid})`);
191
- try {
192
- if (util.tmuxSession) {
193
- try {
194
- await killTmuxSession(util.tmuxSession, util.pid);
195
- stopped++;
196
- }
197
- catch {
198
- if (await isProcessRunning(util.pid)) {
199
- await killProcess(util.pid);
200
- stopped++;
201
- }
202
- }
203
- }
204
- else if (await isProcessRunning(util.pid)) {
205
- await killProcess(util.pid);
73
+ // Stop all builderskill tmux sessions, then Tower terminals
74
+ for (const builder of state.builders) {
75
+ if (builder.tmuxSession) {
76
+ logger.info(`Stopping builder ${builder.id}...`);
77
+ try {
78
+ await killTmuxSession(builder.tmuxSession);
206
79
  stopped++;
207
80
  }
81
+ catch {
82
+ // Session may already be gone
83
+ }
208
84
  }
209
- catch (error) {
210
- logger.warn(`Failed to stop util ${util.id}: ${error}`);
85
+ if (towerRunning && builder.terminalId) {
86
+ try {
87
+ await client.killTerminal(builder.terminalId);
88
+ if (!builder.tmuxSession)
89
+ stopped++;
90
+ }
91
+ catch { /* best-effort */ }
211
92
  }
212
93
  }
213
- // Stop all annotationsuse tree-kill since these are standalone node servers
214
- for (const annotation of state.annotations) {
215
- logger.info(`Stopping annotation ${annotation.id} (PID: ${annotation.pid})`);
216
- try {
217
- if (await isProcessRunning(annotation.pid)) {
218
- await killProcessTree(annotation.pid);
94
+ // Stop all utils — kill tmux sessions, then Tower terminals
95
+ for (const util of state.utils) {
96
+ if (util.tmuxSession) {
97
+ logger.info(`Stopping util ${util.id}...`);
98
+ try {
99
+ await killTmuxSession(util.tmuxSession);
219
100
  stopped++;
220
101
  }
102
+ catch {
103
+ // Session may already be gone
104
+ }
221
105
  }
222
- catch (error) {
223
- logger.warn(`Failed to stop annotation ${annotation.id}: ${error}`);
224
- }
225
- }
226
- // Clear state
227
- clearState();
228
- // Find and kill orphan processes (not in state but running for this project)
229
- const orphans = await findOrphanProcesses(trackedPids);
230
- if (orphans.length > 0) {
231
- logger.blank();
232
- logger.info(`Found ${orphans.length} orphan process(es)`);
233
- for (const pid of orphans) {
106
+ if (towerRunning && util.terminalId) {
234
107
  try {
235
- if (await isProcessRunning(pid)) {
236
- logger.info(` Killing orphan PID ${pid}`);
237
- await killProcessTree(pid);
108
+ await client.killTerminal(util.terminalId);
109
+ if (!util.tmuxSession)
238
110
  stopped++;
239
- }
240
- }
241
- catch (error) {
242
- logger.warn(` Failed to kill orphan ${pid}: ${error}`);
243
111
  }
112
+ catch { /* best-effort */ }
244
113
  }
245
114
  }
115
+ // Clear state
116
+ clearState();
246
117
  logger.blank();
247
118
  if (stopped > 0) {
248
119
  logger.success(`Stopped ${stopped} process(es)`);
@@ -1 +1 @@
1
- {"version":3,"file":"stop.js","sourceRoot":"","sources":["../../../src/agent-farm/commands/stop.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stop.js","sourceRoot":"","sources":["../../../src/agent-farm/commands/stop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Cloud Tower Registration Commands (Spec 0097 Phase 5)
3
+ *
4
+ * Implements `af tower register`, `af tower register --reauth`,
5
+ * `af tower deregister`, and cloud status display for `af tower status`.
6
+ */
7
+ /**
8
+ * Get tunnel status from the running tower daemon.
9
+ */
10
+ export declare function getTunnelStatus(port?: number): Promise<{
11
+ registered: boolean;
12
+ state: string;
13
+ uptime: number | null;
14
+ towerId: string | null;
15
+ towerName: string | null;
16
+ serverUrl: string | null;
17
+ accessUrl: string | null;
18
+ } | null>;
19
+ export interface TowerRegisterOptions {
20
+ reauth?: boolean;
21
+ port?: number;
22
+ }
23
+ /**
24
+ * Register this tower with codevos.ai.
25
+ *
26
+ * Flow:
27
+ * 1. Check existing registration
28
+ * 2. Start ephemeral HTTP server for browser callback
29
+ * 3. Open browser to codevos.ai registration page
30
+ * 4. Wait for callback (2 min timeout), fallback to manual token paste
31
+ * 5. Prompt for tower name (skip on --reauth)
32
+ * 6. Exchange token for API key
33
+ * 7. Write cloud-config.json
34
+ * 8. Signal tower daemon if running
35
+ */
36
+ export declare function towerRegister(options?: TowerRegisterOptions): Promise<void>;
37
+ /**
38
+ * Deregister this tower from codevos.ai.
39
+ */
40
+ export declare function towerDeregister(options?: {
41
+ port?: number;
42
+ }): Promise<void>;
43
+ /**
44
+ * Display cloud connection status.
45
+ */
46
+ export declare function towerCloudStatus(port?: number): Promise<void>;
47
+ //# sourceMappingURL=tower-cloud.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tower-cloud.d.ts","sourceRoot":"","sources":["../../../src/agent-farm/commands/tower-cloud.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgGH;;GAEG;AACH,wBAAsB,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5D,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,GAAG,IAAI,CAAC,CAYR;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CAAC,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6FrF;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CA4CpF;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgCnE"}
@@ -0,0 +1,316 @@
1
+ /**
2
+ * Cloud Tower Registration Commands (Spec 0097 Phase 5)
3
+ *
4
+ * Implements `af tower register`, `af tower register --reauth`,
5
+ * `af tower deregister`, and cloud status display for `af tower status`.
6
+ */
7
+ import http from 'node:http';
8
+ import { hostname } from 'node:os';
9
+ import { createInterface } from 'node:readline';
10
+ import { logger, fatal } from '../utils/logger.js';
11
+ import { openBrowser } from '../utils/shell.js';
12
+ import { readCloudConfig, writeCloudConfig, deleteCloudConfig, maskApiKey, } from '../lib/cloud-config.js';
13
+ const CODEVOS_URL = process.env.CODEVOS_URL || 'https://codevos.ai';
14
+ const DEFAULT_TOWER_PORT = 4100;
15
+ const CALLBACK_TIMEOUT_MS = 120_000; // 2 minutes
16
+ /**
17
+ * Prompt the user for input via stdin.
18
+ */
19
+ function prompt(question) {
20
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
21
+ return new Promise((resolve) => {
22
+ rl.question(question, (answer) => {
23
+ rl.close();
24
+ resolve(answer.trim());
25
+ });
26
+ });
27
+ }
28
+ /**
29
+ * Prompt for yes/no confirmation. Returns true if user answers y/yes.
30
+ */
31
+ async function confirm(question) {
32
+ const answer = await prompt(question);
33
+ return answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes';
34
+ }
35
+ /**
36
+ * Generate a stable machine ID from hostname + platform.
37
+ */
38
+ function getMachineId() {
39
+ const { platform, arch } = process;
40
+ return `${hostname()}-${platform}-${arch}`;
41
+ }
42
+ /**
43
+ * Exchange a registration token for API key and tower ID.
44
+ */
45
+ async function redeemToken(serverUrl, token, towerName, machineId) {
46
+ const url = `${serverUrl}/api/towers/register/redeem`;
47
+ const body = JSON.stringify({ token, name: towerName, machineId });
48
+ const response = await fetch(url, {
49
+ method: 'POST',
50
+ headers: { 'Content-Type': 'application/json' },
51
+ body,
52
+ signal: AbortSignal.timeout(30_000),
53
+ });
54
+ if (!response.ok) {
55
+ const text = await response.text().catch(() => '');
56
+ throw new Error(`Registration failed (${response.status}): ${text || response.statusText}`);
57
+ }
58
+ const data = (await response.json());
59
+ if (!data.towerId || !data.apiKey) {
60
+ throw new Error('Invalid response from registration server: missing towerId or apiKey');
61
+ }
62
+ return { towerId: data.towerId, apiKey: data.apiKey };
63
+ }
64
+ /**
65
+ * Signal the running tower daemon to connect/disconnect the tunnel.
66
+ */
67
+ async function signalTower(endpoint, port) {
68
+ const towerPort = port || DEFAULT_TOWER_PORT;
69
+ try {
70
+ await fetch(`http://127.0.0.1:${towerPort}/api/tunnel/${endpoint}`, {
71
+ method: 'POST',
72
+ signal: AbortSignal.timeout(5_000),
73
+ });
74
+ }
75
+ catch {
76
+ // Tower may not be running — that's fine
77
+ }
78
+ }
79
+ /**
80
+ * Get tunnel status from the running tower daemon.
81
+ */
82
+ export async function getTunnelStatus(port) {
83
+ const towerPort = port || DEFAULT_TOWER_PORT;
84
+ try {
85
+ const response = await fetch(`http://127.0.0.1:${towerPort}/api/tunnel/status`, { signal: AbortSignal.timeout(3_000) });
86
+ if (!response.ok)
87
+ return null;
88
+ return (await response.json());
89
+ }
90
+ catch {
91
+ return null;
92
+ }
93
+ }
94
+ /**
95
+ * Register this tower with codevos.ai.
96
+ *
97
+ * Flow:
98
+ * 1. Check existing registration
99
+ * 2. Start ephemeral HTTP server for browser callback
100
+ * 3. Open browser to codevos.ai registration page
101
+ * 4. Wait for callback (2 min timeout), fallback to manual token paste
102
+ * 5. Prompt for tower name (skip on --reauth)
103
+ * 6. Exchange token for API key
104
+ * 7. Write cloud-config.json
105
+ * 8. Signal tower daemon if running
106
+ */
107
+ export async function towerRegister(options = {}) {
108
+ const existing = readCloudConfig();
109
+ // Check existing registration
110
+ if (existing && !options.reauth) {
111
+ const proceed = await confirm(`This tower is already registered as '${existing.tower_name}'. Re-register? (y/N) `);
112
+ if (!proceed) {
113
+ logger.info('Registration cancelled.');
114
+ return;
115
+ }
116
+ }
117
+ logger.header('Tower Registration');
118
+ // Start ephemeral callback server
119
+ const callbackServer = await startCallbackServer();
120
+ const callbackUrl = `http://localhost:${callbackServer.port}/callback`;
121
+ const callbackParam = `callback=${encodeURIComponent(callbackUrl)}`;
122
+ const browserUrl = options.reauth
123
+ ? `${CODEVOS_URL}/towers/register?reauth=true&${callbackParam}`
124
+ : `${CODEVOS_URL}/towers/register?${callbackParam}`;
125
+ logger.info('Opening browser for authentication...');
126
+ logger.kv('URL', browserUrl);
127
+ try {
128
+ await openBrowser(browserUrl);
129
+ }
130
+ catch {
131
+ logger.warn('Could not open browser automatically.');
132
+ logger.info(`Open this URL manually: ${browserUrl}`);
133
+ }
134
+ logger.info('Waiting for authentication (2 minute timeout)...');
135
+ // Wait for callback or timeout
136
+ let token = await callbackServer.waitForToken(CALLBACK_TIMEOUT_MS);
137
+ if (!token) {
138
+ // Fallback: manual token paste
139
+ logger.warn('Browser callback timed out.');
140
+ token = await prompt('Paste registration token from browser: ');
141
+ if (!token) {
142
+ fatal('No token provided. Registration cancelled.');
143
+ }
144
+ }
145
+ // Prompt for tower name (skip on reauth)
146
+ let towerName;
147
+ if (options.reauth && existing) {
148
+ towerName = existing.tower_name;
149
+ logger.kv('Tower name', towerName);
150
+ }
151
+ else {
152
+ const defaultName = hostname().toLowerCase().replace(/[^a-z0-9-]/g, '-');
153
+ towerName = await prompt(`Tower name (default: ${defaultName}): `);
154
+ if (!towerName)
155
+ towerName = defaultName;
156
+ }
157
+ // Exchange token for API key
158
+ // Explicit CODEVOS_URL env var takes priority over existing config (allows migration)
159
+ const serverUrl = process.env.CODEVOS_URL || existing?.server_url || 'https://codevos.ai';
160
+ logger.info('Exchanging token...');
161
+ let towerId;
162
+ let apiKey;
163
+ try {
164
+ ({ towerId, apiKey } = await redeemToken(serverUrl, token, towerName, getMachineId()));
165
+ }
166
+ catch (err) {
167
+ fatal(`Token exchange failed: ${err.message}`);
168
+ }
169
+ // Write config
170
+ const config = {
171
+ tower_id: towerId,
172
+ tower_name: towerName,
173
+ api_key: apiKey,
174
+ server_url: serverUrl,
175
+ };
176
+ writeCloudConfig(config);
177
+ // Signal tower daemon if running
178
+ await signalTower('connect', options.port);
179
+ // Print success
180
+ const accessUrl = `${serverUrl}/t/${towerName}/`;
181
+ logger.blank();
182
+ logger.success(`Tower '${towerName}' registered successfully.`);
183
+ logger.kv('Tower ID', towerId);
184
+ logger.kv('API Key', maskApiKey(apiKey));
185
+ logger.kv('Access URL', accessUrl);
186
+ }
187
+ /**
188
+ * Deregister this tower from codevos.ai.
189
+ */
190
+ export async function towerDeregister(options = {}) {
191
+ const config = readCloudConfig();
192
+ if (!config) {
193
+ fatal('Tower is not registered. Nothing to deregister.');
194
+ }
195
+ const proceed = await confirm(`Deregister tower '${config.tower_name}' from codevos.ai? (y/N) `);
196
+ if (!proceed) {
197
+ logger.info('Deregistration cancelled.');
198
+ return;
199
+ }
200
+ // Call server to deregister
201
+ try {
202
+ const response = await fetch(`${config.server_url}/api/towers/${config.tower_id}`, {
203
+ method: 'DELETE',
204
+ headers: {
205
+ Authorization: `Bearer ${config.api_key}`,
206
+ },
207
+ signal: AbortSignal.timeout(30_000),
208
+ });
209
+ if (!response.ok && response.status !== 404) {
210
+ const text = await response.text().catch(() => '');
211
+ logger.warn(`Server deregistration returned ${response.status}: ${text || response.statusText}`);
212
+ }
213
+ }
214
+ catch (err) {
215
+ logger.warn(`Could not reach codevos.ai: ${err.message}. Removing local config anyway.`);
216
+ }
217
+ // Delete local config
218
+ deleteCloudConfig();
219
+ // Signal tower daemon to disconnect
220
+ await signalTower('disconnect', options.port);
221
+ logger.blank();
222
+ logger.success('Tower deregistered successfully.');
223
+ }
224
+ /**
225
+ * Display cloud connection status.
226
+ */
227
+ export async function towerCloudStatus(port) {
228
+ const config = readCloudConfig();
229
+ if (!config) {
230
+ logger.blank();
231
+ logger.info('Cloud Registration: not registered. Run \'af tower register\' to connect to codevos.ai.');
232
+ return;
233
+ }
234
+ logger.blank();
235
+ logger.header('Cloud Connection');
236
+ logger.kv('Registration', 'registered');
237
+ logger.kv('Tower Name', config.tower_name);
238
+ logger.kv('Tower ID', config.tower_id);
239
+ logger.kv('Server', config.server_url);
240
+ logger.kv('API Key', maskApiKey(config.api_key));
241
+ // Try to get live tunnel status from daemon
242
+ const status = await getTunnelStatus(port);
243
+ if (status) {
244
+ logger.kv('Connection', status.state);
245
+ if (status.uptime !== null) {
246
+ logger.kv('Uptime', formatUptime(status.uptime));
247
+ }
248
+ if (status.accessUrl) {
249
+ logger.kv('Access URL', status.accessUrl);
250
+ }
251
+ }
252
+ else {
253
+ logger.kv('Connection', 'unknown (tower not running)');
254
+ logger.kv('Access URL', `${config.server_url}/t/${config.tower_name}/`);
255
+ }
256
+ }
257
+ /**
258
+ * Format uptime in milliseconds to a human-readable string.
259
+ */
260
+ function formatUptime(ms) {
261
+ const seconds = Math.floor(ms / 1000);
262
+ if (seconds < 60)
263
+ return `${seconds}s`;
264
+ if (seconds < 3600)
265
+ return `${Math.floor(seconds / 60)}m ${seconds % 60}s`;
266
+ const hours = Math.floor(seconds / 3600);
267
+ const mins = Math.floor((seconds % 3600) / 60);
268
+ return `${hours}h ${mins}m`;
269
+ }
270
+ function startCallbackServer() {
271
+ return new Promise((resolve) => {
272
+ let tokenResolve = null;
273
+ const server = http.createServer((req, res) => {
274
+ const url = new URL(req.url || '/', `http://localhost`);
275
+ if (url.pathname === '/callback') {
276
+ const token = url.searchParams.get('token');
277
+ res.writeHead(200, { 'Content-Type': 'text/html' });
278
+ res.end('<html><body><h1>Registration received!</h1><p>You can close this tab.</p></body></html>');
279
+ if (token && tokenResolve) {
280
+ const r = tokenResolve;
281
+ tokenResolve = null;
282
+ r(token);
283
+ }
284
+ }
285
+ else {
286
+ res.writeHead(404);
287
+ res.end();
288
+ }
289
+ });
290
+ server.listen(0, '127.0.0.1', () => {
291
+ const addr = server.address();
292
+ resolve({
293
+ port: addr.port,
294
+ waitForToken(timeoutMs) {
295
+ return new Promise((r) => {
296
+ tokenResolve = (token) => {
297
+ server.close();
298
+ r(token);
299
+ };
300
+ setTimeout(() => {
301
+ if (tokenResolve) {
302
+ tokenResolve = null;
303
+ server.close();
304
+ r(null);
305
+ }
306
+ }, timeoutMs);
307
+ });
308
+ },
309
+ close() {
310
+ server.close();
311
+ },
312
+ });
313
+ });
314
+ });
315
+ }
316
+ //# sourceMappingURL=tower-cloud.js.map