@cluesmith/codev 2.0.0-rc.3 → 2.0.0-rc.33

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 (315) hide show
  1. package/bin/porch.js +6 -35
  2. package/dashboard/dist/assets/index-CXwnJkPh.css +32 -0
  3. package/dashboard/dist/assets/index-D429K6qO.js +120 -0
  4. package/dashboard/dist/assets/index-D429K6qO.js.map +1 -0
  5. package/dashboard/dist/index.html +13 -0
  6. package/dist/agent-farm/cli.d.ts.map +1 -1
  7. package/dist/agent-farm/cli.js +74 -64
  8. package/dist/agent-farm/cli.js.map +1 -1
  9. package/dist/agent-farm/commands/architect.d.ts.map +1 -1
  10. package/dist/agent-farm/commands/architect.js +0 -2
  11. package/dist/agent-farm/commands/architect.js.map +1 -1
  12. package/dist/agent-farm/commands/attach.d.ts +13 -0
  13. package/dist/agent-farm/commands/attach.d.ts.map +1 -0
  14. package/dist/agent-farm/commands/attach.js +179 -0
  15. package/dist/agent-farm/commands/attach.js.map +1 -0
  16. package/dist/agent-farm/commands/cleanup.d.ts.map +1 -1
  17. package/dist/agent-farm/commands/cleanup.js +30 -3
  18. package/dist/agent-farm/commands/cleanup.js.map +1 -1
  19. package/dist/agent-farm/commands/consult.js +1 -1
  20. package/dist/agent-farm/commands/consult.js.map +1 -1
  21. package/dist/agent-farm/commands/index.d.ts +2 -2
  22. package/dist/agent-farm/commands/index.d.ts.map +1 -1
  23. package/dist/agent-farm/commands/index.js +2 -2
  24. package/dist/agent-farm/commands/index.js.map +1 -1
  25. package/dist/agent-farm/commands/{util.d.ts → shell.d.ts} +5 -5
  26. package/dist/agent-farm/commands/shell.d.ts.map +1 -0
  27. package/dist/agent-farm/commands/{util.js → shell.js} +23 -36
  28. package/dist/agent-farm/commands/shell.js.map +1 -0
  29. package/dist/agent-farm/commands/spawn.d.ts.map +1 -1
  30. package/dist/agent-farm/commands/spawn.js +455 -217
  31. package/dist/agent-farm/commands/spawn.js.map +1 -1
  32. package/dist/agent-farm/commands/start.d.ts.map +1 -1
  33. package/dist/agent-farm/commands/start.js +21 -74
  34. package/dist/agent-farm/commands/start.js.map +1 -1
  35. package/dist/agent-farm/commands/stop.d.ts.map +1 -1
  36. package/dist/agent-farm/commands/stop.js +79 -10
  37. package/dist/agent-farm/commands/stop.js.map +1 -1
  38. package/dist/agent-farm/commands/tower.d.ts.map +1 -1
  39. package/dist/agent-farm/commands/tower.js +2 -1
  40. package/dist/agent-farm/commands/tower.js.map +1 -1
  41. package/dist/agent-farm/db/index.d.ts.map +1 -1
  42. package/dist/agent-farm/db/index.js +15 -0
  43. package/dist/agent-farm/db/index.js.map +1 -1
  44. package/dist/agent-farm/db/schema.d.ts +1 -1
  45. package/dist/agent-farm/db/schema.d.ts.map +1 -1
  46. package/dist/agent-farm/db/schema.js +6 -3
  47. package/dist/agent-farm/db/schema.js.map +1 -1
  48. package/dist/agent-farm/db/types.d.ts +3 -0
  49. package/dist/agent-farm/db/types.d.ts.map +1 -1
  50. package/dist/agent-farm/db/types.js +3 -0
  51. package/dist/agent-farm/db/types.js.map +1 -1
  52. package/dist/agent-farm/hq-connector.d.ts +2 -2
  53. package/dist/agent-farm/hq-connector.js +2 -2
  54. package/dist/agent-farm/servers/dashboard-server.js +412 -131
  55. package/dist/agent-farm/servers/dashboard-server.js.map +1 -1
  56. package/dist/agent-farm/servers/tower-server.js +353 -16
  57. package/dist/agent-farm/servers/tower-server.js.map +1 -1
  58. package/dist/agent-farm/state.d.ts +4 -10
  59. package/dist/agent-farm/state.d.ts.map +1 -1
  60. package/dist/agent-farm/state.js +30 -31
  61. package/dist/agent-farm/state.js.map +1 -1
  62. package/dist/agent-farm/types.d.ts +48 -0
  63. package/dist/agent-farm/types.d.ts.map +1 -1
  64. package/dist/agent-farm/utils/config.d.ts.map +1 -1
  65. package/dist/agent-farm/utils/config.js +12 -11
  66. package/dist/agent-farm/utils/config.js.map +1 -1
  67. package/dist/agent-farm/utils/deps.d.ts.map +1 -1
  68. package/dist/agent-farm/utils/deps.js +0 -16
  69. package/dist/agent-farm/utils/deps.js.map +1 -1
  70. package/dist/agent-farm/utils/notifications.d.ts +30 -0
  71. package/dist/agent-farm/utils/notifications.d.ts.map +1 -0
  72. package/dist/agent-farm/utils/notifications.js +121 -0
  73. package/dist/agent-farm/utils/notifications.js.map +1 -0
  74. package/dist/agent-farm/utils/server-utils.d.ts +2 -1
  75. package/dist/agent-farm/utils/server-utils.d.ts.map +1 -1
  76. package/dist/agent-farm/utils/server-utils.js +11 -1
  77. package/dist/agent-farm/utils/server-utils.js.map +1 -1
  78. package/dist/agent-farm/utils/shell.d.ts +9 -22
  79. package/dist/agent-farm/utils/shell.d.ts.map +1 -1
  80. package/dist/agent-farm/utils/shell.js +34 -34
  81. package/dist/agent-farm/utils/shell.js.map +1 -1
  82. package/dist/agent-farm/utils/terminal-ports.d.ts +1 -1
  83. package/dist/agent-farm/utils/terminal-ports.js +1 -1
  84. package/dist/cli.d.ts.map +1 -1
  85. package/dist/cli.js +5 -54
  86. package/dist/cli.js.map +1 -1
  87. package/dist/commands/adopt.d.ts.map +1 -1
  88. package/dist/commands/adopt.js +39 -4
  89. package/dist/commands/adopt.js.map +1 -1
  90. package/dist/commands/consult/index.d.ts.map +1 -1
  91. package/dist/commands/consult/index.js +63 -3
  92. package/dist/commands/consult/index.js.map +1 -1
  93. package/dist/commands/doctor.d.ts.map +1 -1
  94. package/dist/commands/doctor.js +0 -15
  95. package/dist/commands/doctor.js.map +1 -1
  96. package/dist/commands/init.d.ts.map +1 -1
  97. package/dist/commands/init.js +31 -2
  98. package/dist/commands/init.js.map +1 -1
  99. package/dist/commands/porch/build-counter.d.ts +5 -0
  100. package/dist/commands/porch/build-counter.d.ts.map +1 -0
  101. package/dist/commands/porch/build-counter.js +5 -0
  102. package/dist/commands/porch/build-counter.js.map +1 -0
  103. package/dist/commands/porch/checks.d.ts +16 -29
  104. package/dist/commands/porch/checks.d.ts.map +1 -1
  105. package/dist/commands/porch/checks.js +90 -144
  106. package/dist/commands/porch/checks.js.map +1 -1
  107. package/dist/commands/porch/claude.d.ts +27 -0
  108. package/dist/commands/porch/claude.d.ts.map +1 -0
  109. package/dist/commands/porch/claude.js +107 -0
  110. package/dist/commands/porch/claude.js.map +1 -0
  111. package/dist/commands/porch/index.d.ts +21 -43
  112. package/dist/commands/porch/index.d.ts.map +1 -1
  113. package/dist/commands/porch/index.js +469 -753
  114. package/dist/commands/porch/index.js.map +1 -1
  115. package/dist/commands/porch/plan.d.ts +70 -0
  116. package/dist/commands/porch/plan.d.ts.map +1 -0
  117. package/dist/commands/porch/plan.js +190 -0
  118. package/dist/commands/porch/plan.js.map +1 -0
  119. package/dist/commands/porch/prompts.d.ts +19 -0
  120. package/dist/commands/porch/prompts.d.ts.map +1 -0
  121. package/dist/commands/porch/prompts.js +250 -0
  122. package/dist/commands/porch/prompts.js.map +1 -0
  123. package/dist/commands/porch/protocol.d.ts +59 -0
  124. package/dist/commands/porch/protocol.d.ts.map +1 -0
  125. package/dist/commands/porch/protocol.js +260 -0
  126. package/dist/commands/porch/protocol.js.map +1 -0
  127. package/dist/commands/porch/run.d.ts +40 -0
  128. package/dist/commands/porch/run.d.ts.map +1 -0
  129. package/dist/commands/porch/run.js +893 -0
  130. package/dist/commands/porch/run.js.map +1 -0
  131. package/dist/commands/porch/state.d.ts +23 -112
  132. package/dist/commands/porch/state.d.ts.map +1 -1
  133. package/dist/commands/porch/state.js +81 -685
  134. package/dist/commands/porch/state.js.map +1 -1
  135. package/dist/commands/porch/types.d.ts +72 -173
  136. package/dist/commands/porch/types.d.ts.map +1 -1
  137. package/dist/commands/porch/types.js +2 -1
  138. package/dist/commands/porch/types.js.map +1 -1
  139. package/dist/commands/update.d.ts.map +1 -1
  140. package/dist/commands/update.js +22 -0
  141. package/dist/commands/update.js.map +1 -1
  142. package/dist/lib/scaffold.d.ts +24 -0
  143. package/dist/lib/scaffold.d.ts.map +1 -1
  144. package/dist/lib/scaffold.js +78 -0
  145. package/dist/lib/scaffold.js.map +1 -1
  146. package/dist/terminal/index.d.ts +8 -0
  147. package/dist/terminal/index.d.ts.map +1 -0
  148. package/dist/terminal/index.js +5 -0
  149. package/dist/terminal/index.js.map +1 -0
  150. package/dist/terminal/pty-manager.d.ts +60 -0
  151. package/dist/terminal/pty-manager.d.ts.map +1 -0
  152. package/dist/terminal/pty-manager.js +334 -0
  153. package/dist/terminal/pty-manager.js.map +1 -0
  154. package/dist/terminal/pty-session.d.ts +79 -0
  155. package/dist/terminal/pty-session.d.ts.map +1 -0
  156. package/dist/terminal/pty-session.js +215 -0
  157. package/dist/terminal/pty-session.js.map +1 -0
  158. package/dist/terminal/ring-buffer.d.ts +27 -0
  159. package/dist/terminal/ring-buffer.d.ts.map +1 -0
  160. package/dist/terminal/ring-buffer.js +74 -0
  161. package/dist/terminal/ring-buffer.js.map +1 -0
  162. package/dist/terminal/ws-protocol.d.ts +27 -0
  163. package/dist/terminal/ws-protocol.d.ts.map +1 -0
  164. package/dist/terminal/ws-protocol.js +44 -0
  165. package/dist/terminal/ws-protocol.js.map +1 -0
  166. package/package.json +18 -3
  167. package/skeleton/DEPENDENCIES.md +3 -29
  168. package/skeleton/builders.md +1 -1
  169. package/skeleton/protocol-schema.json +282 -0
  170. package/skeleton/protocols/bugfix/builder-prompt.md +49 -0
  171. package/skeleton/protocols/bugfix/protocol.json +14 -2
  172. package/skeleton/protocols/experiment/builder-prompt.md +47 -0
  173. package/skeleton/protocols/experiment/protocol.json +101 -0
  174. package/skeleton/protocols/maintain/builder-prompt.md +41 -0
  175. package/skeleton/protocols/maintain/prompts/audit.md +111 -0
  176. package/skeleton/protocols/maintain/prompts/clean.md +91 -0
  177. package/skeleton/protocols/maintain/prompts/sync.md +113 -0
  178. package/skeleton/protocols/maintain/prompts/verify.md +110 -0
  179. package/skeleton/protocols/maintain/protocol.json +141 -0
  180. package/skeleton/protocols/maintain/protocol.md +13 -7
  181. package/skeleton/protocols/protocol-schema.json +53 -0
  182. package/skeleton/protocols/spider/builder-prompt.md +53 -0
  183. package/skeleton/protocols/spider/prompts/implement.md +208 -0
  184. package/skeleton/protocols/spider/prompts/plan.md +214 -0
  185. package/skeleton/protocols/spider/prompts/review.md +217 -0
  186. package/skeleton/protocols/spider/prompts/specify.md +192 -0
  187. package/skeleton/protocols/spider/protocol.json +96 -148
  188. package/skeleton/protocols/spider/protocol.md +26 -16
  189. package/skeleton/protocols/spider/templates/plan.md +14 -0
  190. package/skeleton/protocols/tick/builder-prompt.md +51 -0
  191. package/skeleton/protocols/tick/protocol.json +7 -2
  192. package/skeleton/resources/commands/agent-farm.md +25 -43
  193. package/skeleton/resources/commands/overview.md +6 -16
  194. package/skeleton/resources/workflow-reference.md +2 -2
  195. package/skeleton/roles/architect.md +152 -315
  196. package/skeleton/roles/builder.md +109 -218
  197. package/skeleton/templates/AGENTS.md +1 -1
  198. package/skeleton/templates/CLAUDE.md +1 -1
  199. package/skeleton/templates/cheatsheet.md +4 -2
  200. package/templates/dashboard/index.html +17 -43
  201. package/templates/dashboard/js/dialogs.js +7 -7
  202. package/templates/dashboard/js/files.js +2 -2
  203. package/templates/dashboard/js/main.js +3 -3
  204. package/templates/dashboard/js/projects.js +3 -3
  205. package/templates/dashboard/js/tabs.js +1 -1
  206. package/templates/dashboard/js/utils.js +22 -87
  207. package/templates/tower.html +474 -17
  208. package/dist/agent-farm/commands/kickoff.d.ts +0 -19
  209. package/dist/agent-farm/commands/kickoff.d.ts.map +0 -1
  210. package/dist/agent-farm/commands/kickoff.js +0 -323
  211. package/dist/agent-farm/commands/kickoff.js.map +0 -1
  212. package/dist/agent-farm/commands/rename.d.ts +0 -13
  213. package/dist/agent-farm/commands/rename.d.ts.map +0 -1
  214. package/dist/agent-farm/commands/rename.js +0 -33
  215. package/dist/agent-farm/commands/rename.js.map +0 -1
  216. package/dist/agent-farm/commands/tutorial.d.ts +0 -10
  217. package/dist/agent-farm/commands/tutorial.d.ts.map +0 -1
  218. package/dist/agent-farm/commands/tutorial.js +0 -49
  219. package/dist/agent-farm/commands/tutorial.js.map +0 -1
  220. package/dist/agent-farm/commands/util.d.ts.map +0 -1
  221. package/dist/agent-farm/commands/util.js.map +0 -1
  222. package/dist/agent-farm/tutorial/index.d.ts +0 -8
  223. package/dist/agent-farm/tutorial/index.d.ts.map +0 -1
  224. package/dist/agent-farm/tutorial/index.js +0 -8
  225. package/dist/agent-farm/tutorial/index.js.map +0 -1
  226. package/dist/agent-farm/tutorial/prompts.d.ts +0 -57
  227. package/dist/agent-farm/tutorial/prompts.d.ts.map +0 -1
  228. package/dist/agent-farm/tutorial/prompts.js +0 -147
  229. package/dist/agent-farm/tutorial/prompts.js.map +0 -1
  230. package/dist/agent-farm/tutorial/runner.d.ts +0 -52
  231. package/dist/agent-farm/tutorial/runner.d.ts.map +0 -1
  232. package/dist/agent-farm/tutorial/runner.js +0 -204
  233. package/dist/agent-farm/tutorial/runner.js.map +0 -1
  234. package/dist/agent-farm/tutorial/state.d.ts +0 -26
  235. package/dist/agent-farm/tutorial/state.d.ts.map +0 -1
  236. package/dist/agent-farm/tutorial/state.js +0 -89
  237. package/dist/agent-farm/tutorial/state.js.map +0 -1
  238. package/dist/agent-farm/tutorial/steps/first-spec.d.ts +0 -7
  239. package/dist/agent-farm/tutorial/steps/first-spec.d.ts.map +0 -1
  240. package/dist/agent-farm/tutorial/steps/first-spec.js +0 -136
  241. package/dist/agent-farm/tutorial/steps/first-spec.js.map +0 -1
  242. package/dist/agent-farm/tutorial/steps/implementation.d.ts +0 -7
  243. package/dist/agent-farm/tutorial/steps/implementation.d.ts.map +0 -1
  244. package/dist/agent-farm/tutorial/steps/implementation.js +0 -76
  245. package/dist/agent-farm/tutorial/steps/implementation.js.map +0 -1
  246. package/dist/agent-farm/tutorial/steps/index.d.ts +0 -10
  247. package/dist/agent-farm/tutorial/steps/index.d.ts.map +0 -1
  248. package/dist/agent-farm/tutorial/steps/index.js +0 -10
  249. package/dist/agent-farm/tutorial/steps/index.js.map +0 -1
  250. package/dist/agent-farm/tutorial/steps/planning.d.ts +0 -7
  251. package/dist/agent-farm/tutorial/steps/planning.d.ts.map +0 -1
  252. package/dist/agent-farm/tutorial/steps/planning.js +0 -143
  253. package/dist/agent-farm/tutorial/steps/planning.js.map +0 -1
  254. package/dist/agent-farm/tutorial/steps/review.d.ts +0 -7
  255. package/dist/agent-farm/tutorial/steps/review.d.ts.map +0 -1
  256. package/dist/agent-farm/tutorial/steps/review.js +0 -78
  257. package/dist/agent-farm/tutorial/steps/review.js.map +0 -1
  258. package/dist/agent-farm/tutorial/steps/setup.d.ts +0 -7
  259. package/dist/agent-farm/tutorial/steps/setup.d.ts.map +0 -1
  260. package/dist/agent-farm/tutorial/steps/setup.js +0 -126
  261. package/dist/agent-farm/tutorial/steps/setup.js.map +0 -1
  262. package/dist/agent-farm/tutorial/steps/welcome.d.ts +0 -7
  263. package/dist/agent-farm/tutorial/steps/welcome.d.ts.map +0 -1
  264. package/dist/agent-farm/tutorial/steps/welcome.js +0 -50
  265. package/dist/agent-farm/tutorial/steps/welcome.js.map +0 -1
  266. package/dist/commands/pcheck/cache.d.ts +0 -48
  267. package/dist/commands/pcheck/cache.d.ts.map +0 -1
  268. package/dist/commands/pcheck/cache.js +0 -170
  269. package/dist/commands/pcheck/cache.js.map +0 -1
  270. package/dist/commands/pcheck/evaluator.d.ts +0 -15
  271. package/dist/commands/pcheck/evaluator.d.ts.map +0 -1
  272. package/dist/commands/pcheck/evaluator.js +0 -246
  273. package/dist/commands/pcheck/evaluator.js.map +0 -1
  274. package/dist/commands/pcheck/index.d.ts +0 -12
  275. package/dist/commands/pcheck/index.d.ts.map +0 -1
  276. package/dist/commands/pcheck/index.js +0 -249
  277. package/dist/commands/pcheck/index.js.map +0 -1
  278. package/dist/commands/pcheck/parser.d.ts +0 -39
  279. package/dist/commands/pcheck/parser.d.ts.map +0 -1
  280. package/dist/commands/pcheck/parser.js +0 -155
  281. package/dist/commands/pcheck/parser.js.map +0 -1
  282. package/dist/commands/pcheck/types.d.ts +0 -82
  283. package/dist/commands/pcheck/types.d.ts.map +0 -1
  284. package/dist/commands/pcheck/types.js +0 -5
  285. package/dist/commands/pcheck/types.js.map +0 -1
  286. package/dist/commands/porch/consultation.d.ts +0 -56
  287. package/dist/commands/porch/consultation.d.ts.map +0 -1
  288. package/dist/commands/porch/consultation.js +0 -330
  289. package/dist/commands/porch/consultation.js.map +0 -1
  290. package/dist/commands/porch/notifications.d.ts +0 -99
  291. package/dist/commands/porch/notifications.d.ts.map +0 -1
  292. package/dist/commands/porch/notifications.js +0 -223
  293. package/dist/commands/porch/notifications.js.map +0 -1
  294. package/dist/commands/porch/plan-parser.d.ts +0 -38
  295. package/dist/commands/porch/plan-parser.d.ts.map +0 -1
  296. package/dist/commands/porch/plan-parser.js +0 -166
  297. package/dist/commands/porch/plan-parser.js.map +0 -1
  298. package/dist/commands/porch/protocol-loader.d.ts +0 -46
  299. package/dist/commands/porch/protocol-loader.d.ts.map +0 -1
  300. package/dist/commands/porch/protocol-loader.js +0 -249
  301. package/dist/commands/porch/protocol-loader.js.map +0 -1
  302. package/dist/commands/porch/signal-parser.d.ts +0 -88
  303. package/dist/commands/porch/signal-parser.d.ts.map +0 -1
  304. package/dist/commands/porch/signal-parser.js +0 -148
  305. package/dist/commands/porch/signal-parser.js.map +0 -1
  306. package/dist/commands/tower.d.ts +0 -16
  307. package/dist/commands/tower.d.ts.map +0 -1
  308. package/dist/commands/tower.js +0 -21
  309. package/dist/commands/tower.js.map +0 -1
  310. package/skeleton/config.json +0 -7
  311. package/skeleton/porch/protocols/bugfix.json +0 -85
  312. package/skeleton/porch/protocols/spider.json +0 -135
  313. package/skeleton/porch/protocols/tick.json +0 -76
  314. package/templates/dashboard/css/activity.css +0 -151
  315. package/templates/dashboard/js/activity.js +0 -112
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Single PTY session: wraps node-pty with ring buffer, disk logging,
3
+ * WebSocket broadcast, and reconnection support.
4
+ */
5
+ import fs from 'node:fs';
6
+ import path from 'node:path';
7
+ import { EventEmitter } from 'node:events';
8
+ import { RingBuffer } from './ring-buffer.js';
9
+ export class PtySession extends EventEmitter {
10
+ config;
11
+ id;
12
+ label;
13
+ createdAt;
14
+ ringBuffer;
15
+ pty = null;
16
+ cols;
17
+ rows;
18
+ exitCode;
19
+ logFd = null;
20
+ logBytes = 0;
21
+ logPath;
22
+ diskLogEnabled;
23
+ diskLogMaxBytes;
24
+ reconnectTimeoutMs;
25
+ disconnectTimer = null;
26
+ clients = new Set();
27
+ constructor(config) {
28
+ super();
29
+ this.config = config;
30
+ this.id = config.id;
31
+ this.label = config.label;
32
+ this.cols = config.cols;
33
+ this.rows = config.rows;
34
+ this.createdAt = new Date().toISOString();
35
+ this.ringBuffer = new RingBuffer(config.ringBufferLines ?? 1000);
36
+ this.diskLogEnabled = config.diskLogEnabled ?? true;
37
+ this.diskLogMaxBytes = config.diskLogMaxBytes ?? 50 * 1024 * 1024;
38
+ this.reconnectTimeoutMs = config.reconnectTimeoutMs ?? 300_000;
39
+ this.logPath = path.join(config.logDir, `${config.id}.log`);
40
+ }
41
+ /** Spawn the PTY process. Must be called after construction. */
42
+ async spawn() {
43
+ // Dynamic import to avoid hard dependency at module level
44
+ const nodePty = await import('node-pty');
45
+ // Ensure log directory exists
46
+ if (this.diskLogEnabled) {
47
+ fs.mkdirSync(path.dirname(this.logPath), { recursive: true });
48
+ this.logFd = fs.openSync(this.logPath, 'a');
49
+ }
50
+ this.pty = nodePty.spawn(this.config.command, this.config.args, {
51
+ name: 'xterm-256color',
52
+ cols: this.cols,
53
+ rows: this.rows,
54
+ cwd: this.config.cwd,
55
+ env: this.config.env,
56
+ });
57
+ this.pty.onData((data) => {
58
+ this.onPtyData(data);
59
+ });
60
+ this.pty.onExit(({ exitCode }) => {
61
+ this.exitCode = exitCode;
62
+ this.emit('exit', exitCode);
63
+ this.cleanup();
64
+ });
65
+ }
66
+ onPtyData(data) {
67
+ // Store in ring buffer
68
+ this.ringBuffer.pushData(data);
69
+ // Write to disk log
70
+ if (this.diskLogEnabled && this.logFd !== null) {
71
+ const buf = Buffer.from(data, 'utf-8');
72
+ if (this.logBytes + buf.length <= this.diskLogMaxBytes) {
73
+ fs.writeSync(this.logFd, buf);
74
+ this.logBytes += buf.length;
75
+ }
76
+ else {
77
+ this.rotateDiskLog();
78
+ fs.writeSync(this.logFd, buf);
79
+ this.logBytes = buf.length;
80
+ }
81
+ }
82
+ // Broadcast to all connected WebSocket clients
83
+ for (const client of this.clients) {
84
+ try {
85
+ client.send(data);
86
+ }
87
+ catch {
88
+ this.clients.delete(client);
89
+ }
90
+ }
91
+ this.emit('data', data);
92
+ }
93
+ rotateDiskLog() {
94
+ if (this.logFd !== null) {
95
+ fs.closeSync(this.logFd);
96
+ }
97
+ const rotatedPath = this.logPath + '.1';
98
+ // Remove old rotation if exists
99
+ try {
100
+ fs.unlinkSync(rotatedPath + '.1');
101
+ }
102
+ catch { /* ignore */ }
103
+ try {
104
+ fs.renameSync(rotatedPath, rotatedPath + '.1');
105
+ }
106
+ catch { /* ignore */ }
107
+ try {
108
+ fs.renameSync(this.logPath, rotatedPath);
109
+ }
110
+ catch { /* ignore */ }
111
+ this.logFd = fs.openSync(this.logPath, 'a');
112
+ this.logBytes = 0;
113
+ }
114
+ /** Write user input to the PTY. */
115
+ write(data) {
116
+ if (this.pty && this.status === 'running') {
117
+ this.pty.write(data);
118
+ }
119
+ }
120
+ /** Resize the PTY. */
121
+ resize(cols, rows) {
122
+ this.cols = cols;
123
+ this.rows = rows;
124
+ if (this.pty && this.status === 'running') {
125
+ this.pty.resize(cols, rows);
126
+ }
127
+ }
128
+ /** Kill the PTY process. */
129
+ kill() {
130
+ if (this.pty && this.status === 'running') {
131
+ try {
132
+ // Kill process group to prevent orphans
133
+ process.kill(-this.pty.pid, 'SIGTERM');
134
+ setTimeout(() => {
135
+ try {
136
+ process.kill(-this.pty.pid, 'SIGKILL');
137
+ }
138
+ catch { /* already dead */ }
139
+ }, 5000);
140
+ }
141
+ catch {
142
+ // Process already exited
143
+ }
144
+ }
145
+ this.cleanup();
146
+ }
147
+ /** Attach a WebSocket client. Returns ring buffer contents for replay. */
148
+ attach(client) {
149
+ this.clients.add(client);
150
+ if (this.disconnectTimer) {
151
+ clearTimeout(this.disconnectTimer);
152
+ this.disconnectTimer = null;
153
+ }
154
+ return this.ringBuffer.getAll();
155
+ }
156
+ /** Attach with resume from a specific sequence number. */
157
+ attachResume(client, sinceSeq) {
158
+ this.clients.add(client);
159
+ if (this.disconnectTimer) {
160
+ clearTimeout(this.disconnectTimer);
161
+ this.disconnectTimer = null;
162
+ }
163
+ return this.ringBuffer.getSince(sinceSeq);
164
+ }
165
+ /** Detach a WebSocket client. Starts disconnect timer if no clients remain. */
166
+ detach(client) {
167
+ this.clients.delete(client);
168
+ if (this.clients.size === 0 && this.status === 'running') {
169
+ this.disconnectTimer = setTimeout(() => {
170
+ this.emit('timeout');
171
+ this.kill();
172
+ }, this.reconnectTimeoutMs);
173
+ }
174
+ }
175
+ get status() {
176
+ return this.exitCode === undefined ? 'running' : 'exited';
177
+ }
178
+ get pid() {
179
+ return this.pty?.pid ?? -1;
180
+ }
181
+ get info() {
182
+ return {
183
+ id: this.id,
184
+ pid: this.pid,
185
+ cols: this.cols,
186
+ rows: this.rows,
187
+ label: this.label,
188
+ status: this.status,
189
+ createdAt: this.createdAt,
190
+ exitCode: this.exitCode,
191
+ };
192
+ }
193
+ get clientCount() {
194
+ return this.clients.size;
195
+ }
196
+ cleanup() {
197
+ if (this.disconnectTimer) {
198
+ clearTimeout(this.disconnectTimer);
199
+ this.disconnectTimer = null;
200
+ }
201
+ // Release all WebSocket clients
202
+ this.clients.clear();
203
+ // Release ring buffer memory
204
+ this.ringBuffer.clear();
205
+ // Close disk log handle
206
+ if (this.logFd !== null) {
207
+ try {
208
+ fs.closeSync(this.logFd);
209
+ }
210
+ catch { /* ignore */ }
211
+ this.logFd = null;
212
+ }
213
+ }
214
+ }
215
+ //# sourceMappingURL=pty-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pty-session.js","sourceRoot":"","sources":["../../src/terminal/pty-session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Fixed-size circular buffer for storing terminal output lines.
3
+ * Used for reconnection replay — stores last N lines in memory.
4
+ */
5
+ export declare class RingBuffer {
6
+ private readonly capacity;
7
+ private buffer;
8
+ private head;
9
+ private count;
10
+ private seq;
11
+ constructor(capacity?: number);
12
+ /** Push a line into the buffer. Returns the assigned sequence number. */
13
+ push(line: string): number;
14
+ /** Push raw data, splitting on newlines. Returns last sequence number. */
15
+ pushData(data: string): number;
16
+ /** Get all stored lines in order. */
17
+ getAll(): string[];
18
+ /** Get lines starting from a given sequence number (for resume). */
19
+ getSince(sinceSeq: number): string[];
20
+ /** Current sequence number (last written). */
21
+ get currentSeq(): number;
22
+ /** Number of lines currently stored. */
23
+ get size(): number;
24
+ /** Clear the buffer and release memory. */
25
+ clear(): void;
26
+ }
27
+ //# sourceMappingURL=ring-buffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ring-buffer.d.ts","sourceRoot":"","sources":["../../src/terminal/ring-buffer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,qBAAa,UAAU;IAMT,OAAO,CAAC,QAAQ,CAAC,QAAQ;IALrC,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,GAAG,CAAa;gBAEK,QAAQ,GAAE,MAAa;IAIpD,yEAAyE;IACzE,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAW1B,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAS9B,qCAAqC;IACrC,MAAM,IAAI,MAAM,EAAE;IAQlB,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE;IAcpC,8CAA8C;IAC9C,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,wCAAwC;IACxC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,2CAA2C;IAC3C,KAAK,IAAI,IAAI;CAMd"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Fixed-size circular buffer for storing terminal output lines.
3
+ * Used for reconnection replay — stores last N lines in memory.
4
+ */
5
+ export class RingBuffer {
6
+ capacity;
7
+ buffer;
8
+ head = 0;
9
+ count = 0;
10
+ seq = 0; // monotonically increasing sequence number
11
+ constructor(capacity = 1000) {
12
+ this.capacity = capacity;
13
+ this.buffer = new Array(capacity);
14
+ }
15
+ /** Push a line into the buffer. Returns the assigned sequence number. */
16
+ push(line) {
17
+ const index = (this.head + this.count) % this.capacity;
18
+ this.buffer[index] = line;
19
+ if (this.count < this.capacity) {
20
+ this.count++;
21
+ }
22
+ else {
23
+ this.head = (this.head + 1) % this.capacity;
24
+ }
25
+ return ++this.seq;
26
+ }
27
+ /** Push raw data, splitting on newlines. Returns last sequence number. */
28
+ pushData(data) {
29
+ const lines = data.split('\n');
30
+ let lastSeq = this.seq;
31
+ for (const line of lines) {
32
+ lastSeq = this.push(line);
33
+ }
34
+ return lastSeq;
35
+ }
36
+ /** Get all stored lines in order. */
37
+ getAll() {
38
+ const result = [];
39
+ for (let i = 0; i < this.count; i++) {
40
+ result.push(this.buffer[(this.head + i) % this.capacity]);
41
+ }
42
+ return result;
43
+ }
44
+ /** Get lines starting from a given sequence number (for resume). */
45
+ getSince(sinceSeq) {
46
+ const linesAvailable = this.count;
47
+ const oldestSeq = this.seq - linesAvailable + 1;
48
+ const startSeq = Math.max(sinceSeq + 1, oldestSeq);
49
+ if (startSeq > this.seq)
50
+ return [];
51
+ const skip = startSeq - oldestSeq;
52
+ const result = [];
53
+ for (let i = skip; i < this.count; i++) {
54
+ result.push(this.buffer[(this.head + i) % this.capacity]);
55
+ }
56
+ return result;
57
+ }
58
+ /** Current sequence number (last written). */
59
+ get currentSeq() {
60
+ return this.seq;
61
+ }
62
+ /** Number of lines currently stored. */
63
+ get size() {
64
+ return this.count;
65
+ }
66
+ /** Clear the buffer and release memory. */
67
+ clear() {
68
+ this.buffer = [];
69
+ this.head = 0;
70
+ this.count = 0;
71
+ // Don't reset seq — it should be monotonic
72
+ }
73
+ }
74
+ //# sourceMappingURL=ring-buffer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ring-buffer.js","sourceRoot":"","sources":["../../src/terminal/ring-buffer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * WebSocket frame encoding/decoding for terminal communication.
3
+ *
4
+ * Hybrid protocol:
5
+ * - 0x00 prefix: Control frame (remainder is UTF-8 JSON)
6
+ * - 0x01 prefix: Data frame (remainder is raw PTY bytes)
7
+ */
8
+ export declare const FRAME_CONTROL = 0;
9
+ export declare const FRAME_DATA = 1;
10
+ export interface ControlMessage {
11
+ type: 'resize' | 'ping' | 'pong' | 'pause' | 'resume' | 'error';
12
+ payload: Record<string, unknown>;
13
+ }
14
+ /** Encode a control message into a binary frame. */
15
+ export declare function encodeControl(msg: ControlMessage): Buffer;
16
+ /** Encode raw PTY data into a binary frame. */
17
+ export declare function encodeData(data: Buffer | string): Buffer;
18
+ export type DecodedFrame = {
19
+ type: 'control';
20
+ message: ControlMessage;
21
+ } | {
22
+ type: 'data';
23
+ data: Buffer;
24
+ };
25
+ /** Decode a received WebSocket frame. */
26
+ export declare function decodeFrame(frame: Buffer): DecodedFrame;
27
+ //# sourceMappingURL=ws-protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws-protocol.d.ts","sourceRoot":"","sources":["../../src/terminal/ws-protocol.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,eAAO,MAAM,aAAa,IAAO,CAAC;AAClC,eAAO,MAAM,UAAU,IAAO,CAAC;AAE/B,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IAChE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,oDAAoD;AACpD,wBAAgB,aAAa,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAOzD;AAED,+CAA+C;AAC/C,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAMxD;AAED,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnC,yCAAyC;AACzC,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAmBvD"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * WebSocket frame encoding/decoding for terminal communication.
3
+ *
4
+ * Hybrid protocol:
5
+ * - 0x00 prefix: Control frame (remainder is UTF-8 JSON)
6
+ * - 0x01 prefix: Data frame (remainder is raw PTY bytes)
7
+ */
8
+ export const FRAME_CONTROL = 0x00;
9
+ export const FRAME_DATA = 0x01;
10
+ /** Encode a control message into a binary frame. */
11
+ export function encodeControl(msg) {
12
+ const json = JSON.stringify(msg);
13
+ const jsonBuf = Buffer.from(json, 'utf-8');
14
+ const frame = Buffer.allocUnsafe(1 + jsonBuf.length);
15
+ frame[0] = FRAME_CONTROL;
16
+ jsonBuf.copy(frame, 1);
17
+ return frame;
18
+ }
19
+ /** Encode raw PTY data into a binary frame. */
20
+ export function encodeData(data) {
21
+ const dataBuf = typeof data === 'string' ? Buffer.from(data, 'utf-8') : data;
22
+ const frame = Buffer.allocUnsafe(1 + dataBuf.length);
23
+ frame[0] = FRAME_DATA;
24
+ dataBuf.copy(frame, 1);
25
+ return frame;
26
+ }
27
+ /** Decode a received WebSocket frame. */
28
+ export function decodeFrame(frame) {
29
+ if (frame.length === 0) {
30
+ throw new Error('Empty frame');
31
+ }
32
+ const prefix = frame[0];
33
+ const payload = frame.subarray(1);
34
+ if (prefix === FRAME_CONTROL) {
35
+ const json = payload.toString('utf-8');
36
+ const message = JSON.parse(json);
37
+ return { type: 'control', message };
38
+ }
39
+ if (prefix === FRAME_DATA) {
40
+ return { type: 'data', data: payload };
41
+ }
42
+ throw new Error(`Unknown frame prefix: 0x${prefix.toString(16)}`);
43
+ }
44
+ //# sourceMappingURL=ws-protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws-protocol.js","sourceRoot":"","sources":["../../src/terminal/ws-protocol.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC;AAClC,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC;AAO/B,oDAAoD;AACpD,MAAM,UAAU,aAAa,CAAC,GAAmB;IAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IACjC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,KAAK,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC;IACzB,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACvB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,UAAU,CAAC,IAAqB;IAC9C,MAAM,OAAO,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7E,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,KAAK,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC;IACtB,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACvB,OAAO,KAAK,CAAC;AACf,CAAC;AAMD,yCAAyC;AACzC,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,CAAC;IACjC,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACxB,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAElC,IAAI,MAAM,KAAK,aAAa,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACvC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAmB,CAAC;QACnD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;IACtC,CAAC;IAED,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;QAC1B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACzC,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,2BAA2B,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACpE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cluesmith/codev",
3
- "version": "2.0.0-rc.3",
3
+ "version": "2.0.0-rc.33",
4
4
  "description": "Codev CLI - AI-assisted software development framework",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,32 +14,47 @@
14
14
  "dist",
15
15
  "bin",
16
16
  "skeleton",
17
- "templates"
17
+ "templates",
18
+ "dashboard/dist"
18
19
  ],
19
20
  "scripts": {
20
- "build": "tsc && npm run copy-skeleton",
21
+ "clean": "rm -rf dist",
22
+ "build": "npm run clean && tsc && npm run build:dashboard && npm run copy-skeleton",
23
+ "build:dashboard": "cd dashboard && npm install && npm run build",
24
+ "dev:dashboard": "cd dashboard && npm run dev",
21
25
  "copy-skeleton": "rm -rf skeleton && cp -r ../../codev-skeleton skeleton",
22
26
  "dev": "tsx src/cli.ts",
23
27
  "start": "node dist/cli.js",
24
28
  "test": "vitest",
29
+ "test:e2e": "vitest run --config vitest.e2e.config.ts",
30
+ "test:e2e:watch": "vitest --config vitest.e2e.config.ts",
31
+ "postinstall": "node -e \"try{require('fs').chmodSync(require('path').join(require.resolve('node-pty'),'..','..','prebuilds',process.platform+'-'+process.arch,'spawn-helper'),0o755)}catch{}\"",
25
32
  "prepublishOnly": "npm run build"
26
33
  },
27
34
  "dependencies": {
35
+ "@anthropic-ai/claude-agent-sdk": "^0.2.25",
28
36
  "@google/genai": "^1.0.0",
29
37
  "better-sqlite3": "^12.5.0",
30
38
  "chalk": "^5.3.0",
31
39
  "commander": "^12.1.0",
32
40
  "glob": "^11.0.0",
33
41
  "http-proxy": "^1.18.1",
42
+ "js-yaml": "^4.1.0",
43
+ "node-pty": "^1.1.0",
34
44
  "open": "^10.1.0",
45
+ "qrcode-terminal": "^0.12.0",
35
46
  "tree-kill": "^1.2.2",
36
47
  "ws": "^8.18.0"
37
48
  },
38
49
  "devDependencies": {
50
+ "@playwright/test": "^1.58.0",
39
51
  "@types/better-sqlite3": "^7.6.13",
40
52
  "@types/http-proxy": "^1.17.17",
53
+ "@types/js-yaml": "^4.0.9",
41
54
  "@types/node": "^22.10.1",
55
+ "@types/qrcode-terminal": "^0.12.2",
42
56
  "@types/ws": "^8.18.1",
57
+ "playwright": "^1.58.0",
43
58
  "tsx": "^4.19.2",
44
59
  "typescript": "^5.7.2",
45
60
  "vitest": "^4.0.15"
@@ -57,29 +57,6 @@ sudo apt install tmux
57
57
  tmux -V # Should show tmux 3.x or higher
58
58
  ```
59
59
 
60
- ### ttyd
61
-
62
- | Requirement | Value |
63
- |-------------|-------|
64
- | Minimum Version | 1.7.0 |
65
- | Purpose | Web-based terminal for dashboard access |
66
-
67
- **Installation:**
68
-
69
- ```bash
70
- # macOS
71
- brew install ttyd
72
-
73
- # Ubuntu/Debian (build from source)
74
- sudo apt install build-essential cmake git libjson-c-dev libwebsockets-dev
75
- git clone https://github.com/tsl0922/ttyd.git
76
- cd ttyd && mkdir build && cd build
77
- cmake .. && make && sudo make install
78
-
79
- # Verify
80
- ttyd --version # Should show 1.7.x or higher
81
- ```
82
-
83
60
  ### git
84
61
 
85
62
  | Requirement | Value |
@@ -193,7 +170,6 @@ codex --version
193
170
  |------------|-----------------|-----------|
194
171
  | Node.js | 18.0.0 | Yes |
195
172
  | tmux | 3.0 | Yes |
196
- | ttyd | 1.7.0 | Yes |
197
173
  | git | 2.5.0 | Yes |
198
174
  | gh | latest | Yes |
199
175
  | Claude Code | latest | At least one AI CLI |
@@ -210,7 +186,7 @@ All dependencies are available via Homebrew:
210
186
 
211
187
  ```bash
212
188
  # Install all core dependencies at once
213
- brew install node tmux ttyd gh
189
+ brew install node tmux gh
214
190
 
215
191
  # Git is included with Xcode command line tools
216
192
  xcode-select --install
@@ -218,15 +194,13 @@ xcode-select --install
218
194
 
219
195
  ### Ubuntu/Debian
220
196
 
221
- Most dependencies are available via apt, except ttyd which must be built from source:
197
+ Most dependencies are available via apt:
222
198
 
223
199
  ```bash
224
200
  # Core dependencies
225
201
  sudo apt install nodejs npm tmux git
226
202
 
227
203
  # gh requires adding GitHub's apt repository (see above)
228
-
229
- # ttyd must be built from source (see above)
230
204
  ```
231
205
 
232
206
  ### Windows
@@ -267,7 +241,7 @@ sudo apt update
267
241
  sudo apt install tmux
268
242
  ```
269
243
 
270
- ### ttyd connection issues
244
+ ### Terminal connection issues
271
245
 
272
246
  Ensure no firewall is blocking the ports (default: 4200-4299):
273
247
 
@@ -4,7 +4,7 @@ Track active builder agents here. Update manually or via `architect status`.
4
4
 
5
5
  ## Status Values
6
6
 
7
- - **spawning**: Worktree being created, ttyd starting
7
+ - **spawning**: Worktree being created, terminal starting
8
8
  - **implementing**: Builder is working
9
9
  - **blocked**: Builder waiting for architect input
10
10
  - **pr-ready**: Builder has created a PR