@amsterdamdatalabs/enact-factory 0.1.1

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 (644) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +566 -0
  3. package/dist/adapters/agenticLoop.d.ts +90 -0
  4. package/dist/adapters/agenticLoop.d.ts.map +1 -0
  5. package/dist/adapters/agenticLoop.js +219 -0
  6. package/dist/adapters/agenticLoop.js.map +1 -0
  7. package/dist/adapters/base.d.ts +16 -0
  8. package/dist/adapters/base.d.ts.map +1 -0
  9. package/dist/adapters/base.js +135 -0
  10. package/dist/adapters/base.js.map +1 -0
  11. package/dist/adapters/claude.d.ts +13 -0
  12. package/dist/adapters/claude.d.ts.map +1 -0
  13. package/dist/adapters/claude.js +318 -0
  14. package/dist/adapters/claude.js.map +1 -0
  15. package/dist/adapters/codex.d.ts +14 -0
  16. package/dist/adapters/codex.d.ts.map +1 -0
  17. package/dist/adapters/codex.js +366 -0
  18. package/dist/adapters/codex.js.map +1 -0
  19. package/dist/adapters/cryptoQuantAdapter.d.ts +85 -0
  20. package/dist/adapters/cryptoQuantAdapter.d.ts.map +1 -0
  21. package/dist/adapters/cryptoQuantAdapter.js +238 -0
  22. package/dist/adapters/cryptoQuantAdapter.js.map +1 -0
  23. package/dist/adapters/cursor.d.ts +13 -0
  24. package/dist/adapters/cursor.d.ts.map +1 -0
  25. package/dist/adapters/cursor.js +300 -0
  26. package/dist/adapters/cursor.js.map +1 -0
  27. package/dist/adapters/envPath.d.ts +20 -0
  28. package/dist/adapters/envPath.d.ts.map +1 -0
  29. package/dist/adapters/envPath.js +49 -0
  30. package/dist/adapters/envPath.js.map +1 -0
  31. package/dist/adapters/hermes.d.ts +13 -0
  32. package/dist/adapters/hermes.d.ts.map +1 -0
  33. package/dist/adapters/hermes.js +283 -0
  34. package/dist/adapters/hermes.js.map +1 -0
  35. package/dist/adapters/index.d.ts +18 -0
  36. package/dist/adapters/index.d.ts.map +1 -0
  37. package/dist/adapters/index.js +56 -0
  38. package/dist/adapters/index.js.map +1 -0
  39. package/dist/adapters/opencode.d.ts +13 -0
  40. package/dist/adapters/opencode.d.ts.map +1 -0
  41. package/dist/adapters/opencode.js +282 -0
  42. package/dist/adapters/opencode.js.map +1 -0
  43. package/dist/adapters/processRegistry.d.ts +38 -0
  44. package/dist/adapters/processRegistry.d.ts.map +1 -0
  45. package/dist/adapters/processRegistry.js +147 -0
  46. package/dist/adapters/processRegistry.js.map +1 -0
  47. package/dist/adapters/responses.d.ts +16 -0
  48. package/dist/adapters/responses.d.ts.map +1 -0
  49. package/dist/adapters/responses.js +244 -0
  50. package/dist/adapters/responses.js.map +1 -0
  51. package/dist/adapters/streamBuffer.d.ts +59 -0
  52. package/dist/adapters/streamBuffer.d.ts.map +1 -0
  53. package/dist/adapters/streamBuffer.js +123 -0
  54. package/dist/adapters/streamBuffer.js.map +1 -0
  55. package/dist/adapters/tools.d.ts +30 -0
  56. package/dist/adapters/tools.d.ts.map +1 -0
  57. package/dist/adapters/tools.js +219 -0
  58. package/dist/adapters/tools.js.map +1 -0
  59. package/dist/adapters/types.d.ts +82 -0
  60. package/dist/adapters/types.d.ts.map +1 -0
  61. package/dist/adapters/types.js +6 -0
  62. package/dist/adapters/types.js.map +1 -0
  63. package/dist/agents/agentBus.d.ts +160 -0
  64. package/dist/agents/agentBus.d.ts.map +1 -0
  65. package/dist/agents/agentBus.js +350 -0
  66. package/dist/agents/agentBus.js.map +1 -0
  67. package/dist/agents/agentPair.d.ts +215 -0
  68. package/dist/agents/agentPair.d.ts.map +1 -0
  69. package/dist/agents/agentPair.js +456 -0
  70. package/dist/agents/agentPair.js.map +1 -0
  71. package/dist/agents/auditor.d.ts +27 -0
  72. package/dist/agents/auditor.d.ts.map +1 -0
  73. package/dist/agents/auditor.js +238 -0
  74. package/dist/agents/auditor.js.map +1 -0
  75. package/dist/agents/cliStreamParser.d.ts +18 -0
  76. package/dist/agents/cliStreamParser.d.ts.map +1 -0
  77. package/dist/agents/cliStreamParser.js +156 -0
  78. package/dist/agents/cliStreamParser.js.map +1 -0
  79. package/dist/agents/documenter.d.ts +31 -0
  80. package/dist/agents/documenter.d.ts.map +1 -0
  81. package/dist/agents/documenter.js +286 -0
  82. package/dist/agents/documenter.js.map +1 -0
  83. package/dist/agents/draftAnalyzer.d.ts +50 -0
  84. package/dist/agents/draftAnalyzer.d.ts.map +1 -0
  85. package/dist/agents/draftAnalyzer.js +289 -0
  86. package/dist/agents/draftAnalyzer.js.map +1 -0
  87. package/dist/agents/evaluator.d.ts +61 -0
  88. package/dist/agents/evaluator.d.ts.map +1 -0
  89. package/dist/agents/evaluator.js +338 -0
  90. package/dist/agents/evaluator.js.map +1 -0
  91. package/dist/agents/executor.d.ts +33 -0
  92. package/dist/agents/executor.d.ts.map +1 -0
  93. package/dist/agents/executor.js +130 -0
  94. package/dist/agents/executor.js.map +1 -0
  95. package/dist/agents/index.d.ts +10 -0
  96. package/dist/agents/index.d.ts.map +1 -0
  97. package/dist/agents/index.js +10 -0
  98. package/dist/agents/index.js.map +1 -0
  99. package/dist/agents/pairMetrics.d.ts +63 -0
  100. package/dist/agents/pairMetrics.d.ts.map +1 -0
  101. package/dist/agents/pairMetrics.js +232 -0
  102. package/dist/agents/pairMetrics.js.map +1 -0
  103. package/dist/agents/pairPipeline.d.ts +184 -0
  104. package/dist/agents/pairPipeline.d.ts.map +1 -0
  105. package/dist/agents/pairPipeline.js +934 -0
  106. package/dist/agents/pairPipeline.js.map +1 -0
  107. package/dist/agents/pairWebhook.d.ts +59 -0
  108. package/dist/agents/pairWebhook.d.ts.map +1 -0
  109. package/dist/agents/pairWebhook.js +242 -0
  110. package/dist/agents/pairWebhook.js.map +1 -0
  111. package/dist/agents/pipelineFormat.d.ts +8 -0
  112. package/dist/agents/pipelineFormat.d.ts.map +1 -0
  113. package/dist/agents/pipelineFormat.js +65 -0
  114. package/dist/agents/pipelineFormat.js.map +1 -0
  115. package/dist/agents/pipelineGuards.d.ts +23 -0
  116. package/dist/agents/pipelineGuards.d.ts.map +1 -0
  117. package/dist/agents/pipelineGuards.js +257 -0
  118. package/dist/agents/pipelineGuards.js.map +1 -0
  119. package/dist/agents/reviewer.d.ts +37 -0
  120. package/dist/agents/reviewer.d.ts.map +1 -0
  121. package/dist/agents/reviewer.js +214 -0
  122. package/dist/agents/reviewer.js.map +1 -0
  123. package/dist/agents/skillDocumenter.d.ts +23 -0
  124. package/dist/agents/skillDocumenter.d.ts.map +1 -0
  125. package/dist/agents/skillDocumenter.js +219 -0
  126. package/dist/agents/skillDocumenter.js.map +1 -0
  127. package/dist/agents/tester.d.ts +37 -0
  128. package/dist/agents/tester.d.ts.map +1 -0
  129. package/dist/agents/tester.js +309 -0
  130. package/dist/agents/tester.js.map +1 -0
  131. package/dist/automation/autonomousRunner.d.ts +145 -0
  132. package/dist/automation/autonomousRunner.d.ts.map +1 -0
  133. package/dist/automation/autonomousRunner.js +1272 -0
  134. package/dist/automation/autonomousRunner.js.map +1 -0
  135. package/dist/automation/dailyReporter.d.ts +26 -0
  136. package/dist/automation/dailyReporter.d.ts.map +1 -0
  137. package/dist/automation/dailyReporter.js +130 -0
  138. package/dist/automation/dailyReporter.js.map +1 -0
  139. package/dist/automation/index.d.ts +5 -0
  140. package/dist/automation/index.d.ts.map +1 -0
  141. package/dist/automation/index.js +5 -0
  142. package/dist/automation/index.js.map +1 -0
  143. package/dist/automation/longRunningMonitor.d.ts +26 -0
  144. package/dist/automation/longRunningMonitor.d.ts.map +1 -0
  145. package/dist/automation/longRunningMonitor.js +356 -0
  146. package/dist/automation/longRunningMonitor.js.map +1 -0
  147. package/dist/automation/prOwnership.d.ts +18 -0
  148. package/dist/automation/prOwnership.d.ts.map +1 -0
  149. package/dist/automation/prOwnership.js +61 -0
  150. package/dist/automation/prOwnership.js.map +1 -0
  151. package/dist/automation/runnerExecution.d.ts +57 -0
  152. package/dist/automation/runnerExecution.d.ts.map +1 -0
  153. package/dist/automation/runnerExecution.js +701 -0
  154. package/dist/automation/runnerExecution.js.map +1 -0
  155. package/dist/automation/runnerState.d.ts +170 -0
  156. package/dist/automation/runnerState.d.ts.map +1 -0
  157. package/dist/automation/runnerState.js +496 -0
  158. package/dist/automation/runnerState.js.map +1 -0
  159. package/dist/automation/runnerTypes.d.ts +57 -0
  160. package/dist/automation/runnerTypes.d.ts.map +1 -0
  161. package/dist/automation/runnerTypes.js +5 -0
  162. package/dist/automation/runnerTypes.js.map +1 -0
  163. package/dist/automation/scheduler.d.ts +75 -0
  164. package/dist/automation/scheduler.d.ts.map +1 -0
  165. package/dist/automation/scheduler.js +402 -0
  166. package/dist/automation/scheduler.js.map +1 -0
  167. package/dist/azdo/azdo.d.ts +70 -0
  168. package/dist/azdo/azdo.d.ts.map +1 -0
  169. package/dist/azdo/azdo.js +328 -0
  170. package/dist/azdo/azdo.js.map +1 -0
  171. package/dist/azdo/index.d.ts +3 -0
  172. package/dist/azdo/index.d.ts.map +1 -0
  173. package/dist/azdo/index.js +3 -0
  174. package/dist/azdo/index.js.map +1 -0
  175. package/dist/azdo/projectUpdater.d.ts +13 -0
  176. package/dist/azdo/projectUpdater.d.ts.map +1 -0
  177. package/dist/azdo/projectUpdater.js +155 -0
  178. package/dist/azdo/projectUpdater.js.map +1 -0
  179. package/dist/azureDevOps/client.d.ts +75 -0
  180. package/dist/azureDevOps/client.d.ts.map +1 -0
  181. package/dist/azureDevOps/client.js +150 -0
  182. package/dist/azureDevOps/client.js.map +1 -0
  183. package/dist/azureDevOps/hierarchy.d.ts +119 -0
  184. package/dist/azureDevOps/hierarchy.d.ts.map +1 -0
  185. package/dist/azureDevOps/hierarchy.js +470 -0
  186. package/dist/azureDevOps/hierarchy.js.map +1 -0
  187. package/dist/azureDevOps/mapper.d.ts +101 -0
  188. package/dist/azureDevOps/mapper.d.ts.map +1 -0
  189. package/dist/azureDevOps/mapper.js +438 -0
  190. package/dist/azureDevOps/mapper.js.map +1 -0
  191. package/dist/azureDevOps/stateMapping.d.ts +15 -0
  192. package/dist/azureDevOps/stateMapping.d.ts.map +1 -0
  193. package/dist/azureDevOps/stateMapping.js +141 -0
  194. package/dist/azureDevOps/stateMapping.js.map +1 -0
  195. package/dist/cli/authHandler.d.ts +13 -0
  196. package/dist/cli/authHandler.d.ts.map +1 -0
  197. package/dist/cli/authHandler.js +70 -0
  198. package/dist/cli/authHandler.js.map +1 -0
  199. package/dist/cli/checkHandler.d.ts +27 -0
  200. package/dist/cli/checkHandler.d.ts.map +1 -0
  201. package/dist/cli/checkHandler.js +560 -0
  202. package/dist/cli/checkHandler.js.map +1 -0
  203. package/dist/cli/daemon.d.ts +30 -0
  204. package/dist/cli/daemon.d.ts.map +1 -0
  205. package/dist/cli/daemon.js +141 -0
  206. package/dist/cli/daemon.js.map +1 -0
  207. package/dist/cli/factoryCommands.d.ts +3 -0
  208. package/dist/cli/factoryCommands.d.ts.map +1 -0
  209. package/dist/cli/factoryCommands.js +165 -0
  210. package/dist/cli/factoryCommands.js.map +1 -0
  211. package/dist/cli/promptHandler.d.ts +13 -0
  212. package/dist/cli/promptHandler.d.ts.map +1 -0
  213. package/dist/cli/promptHandler.js +193 -0
  214. package/dist/cli/promptHandler.js.map +1 -0
  215. package/dist/cli.d.ts +3 -0
  216. package/dist/cli.d.ts.map +1 -0
  217. package/dist/cli.js +320 -0
  218. package/dist/cli.js.map +1 -0
  219. package/dist/core/agentLifecycle.d.ts +322 -0
  220. package/dist/core/agentLifecycle.d.ts.map +1 -0
  221. package/dist/core/agentLifecycle.js +230 -0
  222. package/dist/core/agentLifecycle.js.map +1 -0
  223. package/dist/core/areaMapping.d.ts +9 -0
  224. package/dist/core/areaMapping.d.ts.map +1 -0
  225. package/dist/core/areaMapping.js +37 -0
  226. package/dist/core/areaMapping.js.map +1 -0
  227. package/dist/core/config.d.ts +469 -0
  228. package/dist/core/config.d.ts.map +1 -0
  229. package/dist/core/config.js +780 -0
  230. package/dist/core/config.js.map +1 -0
  231. package/dist/core/dashboardContract.d.ts +204 -0
  232. package/dist/core/dashboardContract.d.ts.map +1 -0
  233. package/dist/core/dashboardContract.js +205 -0
  234. package/dist/core/dashboardContract.js.map +1 -0
  235. package/dist/core/devopsModel.d.ts +138 -0
  236. package/dist/core/devopsModel.d.ts.map +1 -0
  237. package/dist/core/devopsModel.js +137 -0
  238. package/dist/core/devopsModel.js.map +1 -0
  239. package/dist/core/envFile.d.ts +11 -0
  240. package/dist/core/envFile.d.ts.map +1 -0
  241. package/dist/core/envFile.js +104 -0
  242. package/dist/core/envFile.js.map +1 -0
  243. package/dist/core/eventHub.d.ts +220 -0
  244. package/dist/core/eventHub.d.ts.map +1 -0
  245. package/dist/core/eventHub.js +136 -0
  246. package/dist/core/eventHub.js.map +1 -0
  247. package/dist/core/index.d.ts +8 -0
  248. package/dist/core/index.d.ts.map +1 -0
  249. package/dist/core/index.js +7 -0
  250. package/dist/core/index.js.map +1 -0
  251. package/dist/core/laneExecutionState.d.ts +29 -0
  252. package/dist/core/laneExecutionState.d.ts.map +1 -0
  253. package/dist/core/laneExecutionState.js +18 -0
  254. package/dist/core/laneExecutionState.js.map +1 -0
  255. package/dist/core/laneStatus.d.ts +49 -0
  256. package/dist/core/laneStatus.d.ts.map +1 -0
  257. package/dist/core/laneStatus.js +153 -0
  258. package/dist/core/laneStatus.js.map +1 -0
  259. package/dist/core/prSidecar.d.ts +96 -0
  260. package/dist/core/prSidecar.d.ts.map +1 -0
  261. package/dist/core/prSidecar.js +33 -0
  262. package/dist/core/prSidecar.js.map +1 -0
  263. package/dist/core/runtimeConfig.d.ts +6 -0
  264. package/dist/core/runtimeConfig.d.ts.map +1 -0
  265. package/dist/core/runtimeConfig.js +24 -0
  266. package/dist/core/runtimeConfig.js.map +1 -0
  267. package/dist/core/scmProvider.d.ts +19 -0
  268. package/dist/core/scmProvider.d.ts.map +1 -0
  269. package/dist/core/scmProvider.js +38 -0
  270. package/dist/core/scmProvider.js.map +1 -0
  271. package/dist/core/service.d.ts +10 -0
  272. package/dist/core/service.d.ts.map +1 -0
  273. package/dist/core/service.js +297 -0
  274. package/dist/core/service.js.map +1 -0
  275. package/dist/core/traceCollector.d.ts +105 -0
  276. package/dist/core/traceCollector.d.ts.map +1 -0
  277. package/dist/core/traceCollector.js +141 -0
  278. package/dist/core/traceCollector.js.map +1 -0
  279. package/dist/core/types.d.ts +432 -0
  280. package/dist/core/types.d.ts.map +1 -0
  281. package/dist/core/types.js +2 -0
  282. package/dist/core/types.js.map +1 -0
  283. package/dist/core/workItemMapper.d.ts +39 -0
  284. package/dist/core/workItemMapper.d.ts.map +1 -0
  285. package/dist/core/workItemMapper.js +427 -0
  286. package/dist/core/workItemMapper.js.map +1 -0
  287. package/dist/core/workItemModel.d.ts +120 -0
  288. package/dist/core/workItemModel.d.ts.map +1 -0
  289. package/dist/core/workItemModel.js +104 -0
  290. package/dist/core/workItemModel.js.map +1 -0
  291. package/dist/core/workItemPayload.d.ts +195 -0
  292. package/dist/core/workItemPayload.d.ts.map +1 -0
  293. package/dist/core/workItemPayload.js +24 -0
  294. package/dist/core/workItemPayload.js.map +1 -0
  295. package/dist/core/workspaceConfig.d.ts +57 -0
  296. package/dist/core/workspaceConfig.d.ts.map +1 -0
  297. package/dist/core/workspaceConfig.js +184 -0
  298. package/dist/core/workspaceConfig.js.map +1 -0
  299. package/dist/doctor.d.ts +18 -0
  300. package/dist/doctor.d.ts.map +1 -0
  301. package/dist/doctor.js +34 -0
  302. package/dist/doctor.js.map +1 -0
  303. package/dist/factory/activeSkill.d.ts +11 -0
  304. package/dist/factory/activeSkill.d.ts.map +1 -0
  305. package/dist/factory/activeSkill.js +44 -0
  306. package/dist/factory/activeSkill.js.map +1 -0
  307. package/dist/factory/assignment.d.ts +54 -0
  308. package/dist/factory/assignment.d.ts.map +1 -0
  309. package/dist/factory/assignment.js +94 -0
  310. package/dist/factory/assignment.js.map +1 -0
  311. package/dist/factory/auditLog.d.ts +10 -0
  312. package/dist/factory/auditLog.d.ts.map +1 -0
  313. package/dist/factory/auditLog.js +38 -0
  314. package/dist/factory/auditLog.js.map +1 -0
  315. package/dist/factory/closureRequirements.d.ts +12 -0
  316. package/dist/factory/closureRequirements.d.ts.map +1 -0
  317. package/dist/factory/closureRequirements.js +30 -0
  318. package/dist/factory/closureRequirements.js.map +1 -0
  319. package/dist/factory/delegationPrompt.d.ts +3 -0
  320. package/dist/factory/delegationPrompt.d.ts.map +1 -0
  321. package/dist/factory/delegationPrompt.js +16 -0
  322. package/dist/factory/delegationPrompt.js.map +1 -0
  323. package/dist/factory/http.d.ts +3 -0
  324. package/dist/factory/http.d.ts.map +1 -0
  325. package/dist/factory/http.js +555 -0
  326. package/dist/factory/http.js.map +1 -0
  327. package/dist/factory/lifecyclePushMap.d.ts +4 -0
  328. package/dist/factory/lifecyclePushMap.d.ts.map +1 -0
  329. package/dist/factory/lifecyclePushMap.js +7 -0
  330. package/dist/factory/lifecyclePushMap.js.map +1 -0
  331. package/dist/factory/missions.d.ts +125 -0
  332. package/dist/factory/missions.d.ts.map +1 -0
  333. package/dist/factory/missions.js +304 -0
  334. package/dist/factory/missions.js.map +1 -0
  335. package/dist/factory/mode.d.ts +9 -0
  336. package/dist/factory/mode.d.ts.map +1 -0
  337. package/dist/factory/mode.js +30 -0
  338. package/dist/factory/mode.js.map +1 -0
  339. package/dist/factory/operatorActiveSkill.d.ts +15 -0
  340. package/dist/factory/operatorActiveSkill.d.ts.map +1 -0
  341. package/dist/factory/operatorActiveSkill.js +95 -0
  342. package/dist/factory/operatorActiveSkill.js.map +1 -0
  343. package/dist/factory/paseoDispatcher.d.ts +52 -0
  344. package/dist/factory/paseoDispatcher.d.ts.map +1 -0
  345. package/dist/factory/paseoDispatcher.js +122 -0
  346. package/dist/factory/paseoDispatcher.js.map +1 -0
  347. package/dist/factory/paseoLifecycle.d.ts +32 -0
  348. package/dist/factory/paseoLifecycle.d.ts.map +1 -0
  349. package/dist/factory/paseoLifecycle.js +260 -0
  350. package/dist/factory/paseoLifecycle.js.map +1 -0
  351. package/dist/factory/paths.d.ts +31 -0
  352. package/dist/factory/paths.d.ts.map +1 -0
  353. package/dist/factory/paths.js +139 -0
  354. package/dist/factory/paths.js.map +1 -0
  355. package/dist/factory/progressWatchdog.d.ts +58 -0
  356. package/dist/factory/progressWatchdog.d.ts.map +1 -0
  357. package/dist/factory/progressWatchdog.js +160 -0
  358. package/dist/factory/progressWatchdog.js.map +1 -0
  359. package/dist/factory/roster.d.ts +59 -0
  360. package/dist/factory/roster.d.ts.map +1 -0
  361. package/dist/factory/roster.js +116 -0
  362. package/dist/factory/roster.js.map +1 -0
  363. package/dist/factory/runtime.d.ts +44 -0
  364. package/dist/factory/runtime.d.ts.map +1 -0
  365. package/dist/factory/runtime.js +238 -0
  366. package/dist/factory/runtime.js.map +1 -0
  367. package/dist/factory/sync.d.ts +29 -0
  368. package/dist/factory/sync.d.ts.map +1 -0
  369. package/dist/factory/sync.js +77 -0
  370. package/dist/factory/sync.js.map +1 -0
  371. package/dist/factory/workitemQueues.d.ts +37 -0
  372. package/dist/factory/workitemQueues.d.ts.map +1 -0
  373. package/dist/factory/workitemQueues.js +99 -0
  374. package/dist/factory/workitemQueues.js.map +1 -0
  375. package/dist/factory/workitemTriage.d.ts +9 -0
  376. package/dist/factory/workitemTriage.d.ts.map +1 -0
  377. package/dist/factory/workitemTriage.js +81 -0
  378. package/dist/factory/workitemTriage.js.map +1 -0
  379. package/dist/hooks.d.ts +18 -0
  380. package/dist/hooks.d.ts.map +1 -0
  381. package/dist/hooks.js +96 -0
  382. package/dist/hooks.js.map +1 -0
  383. package/dist/index.d.ts +3 -0
  384. package/dist/index.d.ts.map +1 -0
  385. package/dist/index.js +90 -0
  386. package/dist/index.js.map +1 -0
  387. package/dist/install/agentCatalog.d.ts +7 -0
  388. package/dist/install/agentCatalog.d.ts.map +1 -0
  389. package/dist/install/agentCatalog.js +28 -0
  390. package/dist/install/agentCatalog.js.map +1 -0
  391. package/dist/install/bundlePaths.d.ts +10 -0
  392. package/dist/install/bundlePaths.d.ts.map +1 -0
  393. package/dist/install/bundlePaths.js +30 -0
  394. package/dist/install/bundlePaths.js.map +1 -0
  395. package/dist/install/codex.d.ts +43 -0
  396. package/dist/install/codex.d.ts.map +1 -0
  397. package/dist/install/codex.js +207 -0
  398. package/dist/install/codex.js.map +1 -0
  399. package/dist/install/enactHome.d.ts +37 -0
  400. package/dist/install/enactHome.d.ts.map +1 -0
  401. package/dist/install/enactHome.js +152 -0
  402. package/dist/install/enactHome.js.map +1 -0
  403. package/dist/install/plugins.d.ts +115 -0
  404. package/dist/install/plugins.d.ts.map +1 -0
  405. package/dist/install/plugins.js +259 -0
  406. package/dist/install/plugins.js.map +1 -0
  407. package/dist/install/setup.d.ts +33 -0
  408. package/dist/install/setup.d.ts.map +1 -0
  409. package/dist/install/setup.js +167 -0
  410. package/dist/install/setup.js.map +1 -0
  411. package/dist/locale/en.d.ts +3 -0
  412. package/dist/locale/en.d.ts.map +1 -0
  413. package/dist/locale/en.js +435 -0
  414. package/dist/locale/en.js.map +1 -0
  415. package/dist/locale/index.d.ts +28 -0
  416. package/dist/locale/index.d.ts.map +1 -0
  417. package/dist/locale/index.js +84 -0
  418. package/dist/locale/index.js.map +1 -0
  419. package/dist/locale/prompts/en.d.ts +3 -0
  420. package/dist/locale/prompts/en.d.ts.map +1 -0
  421. package/dist/locale/prompts/en.js +254 -0
  422. package/dist/locale/prompts/en.js.map +1 -0
  423. package/dist/locale/types.d.ts +433 -0
  424. package/dist/locale/types.d.ts.map +1 -0
  425. package/dist/locale/types.js +5 -0
  426. package/dist/locale/types.js.map +1 -0
  427. package/dist/mcp/server.d.ts +489 -0
  428. package/dist/mcp/server.d.ts.map +1 -0
  429. package/dist/mcp/server.js +597 -0
  430. package/dist/mcp/server.js.map +1 -0
  431. package/dist/orchestration/decisionEngine.d.ts +175 -0
  432. package/dist/orchestration/decisionEngine.d.ts.map +1 -0
  433. package/dist/orchestration/decisionEngine.js +471 -0
  434. package/dist/orchestration/decisionEngine.js.map +1 -0
  435. package/dist/orchestration/index.d.ts +5 -0
  436. package/dist/orchestration/index.d.ts.map +1 -0
  437. package/dist/orchestration/index.js +5 -0
  438. package/dist/orchestration/index.js.map +1 -0
  439. package/dist/orchestration/workItemParser.d.ts +67 -0
  440. package/dist/orchestration/workItemParser.d.ts.map +1 -0
  441. package/dist/orchestration/workItemParser.js +560 -0
  442. package/dist/orchestration/workItemParser.js.map +1 -0
  443. package/dist/orchestration/workItemScheduler.d.ts +141 -0
  444. package/dist/orchestration/workItemScheduler.d.ts.map +1 -0
  445. package/dist/orchestration/workItemScheduler.js +317 -0
  446. package/dist/orchestration/workItemScheduler.js.map +1 -0
  447. package/dist/orchestration/workflow.d.ts +145 -0
  448. package/dist/orchestration/workflow.d.ts.map +1 -0
  449. package/dist/orchestration/workflow.js +301 -0
  450. package/dist/orchestration/workflow.js.map +1 -0
  451. package/dist/providers/codexSessions.d.ts +93 -0
  452. package/dist/providers/codexSessions.d.ts.map +1 -0
  453. package/dist/providers/codexSessions.js +366 -0
  454. package/dist/providers/codexSessions.js.map +1 -0
  455. package/dist/registry/bsDetector.d.ts +24 -0
  456. package/dist/registry/bsDetector.d.ts.map +1 -0
  457. package/dist/registry/bsDetector.js +276 -0
  458. package/dist/registry/bsDetector.js.map +1 -0
  459. package/dist/registry/entityScanner.d.ts +36 -0
  460. package/dist/registry/entityScanner.d.ts.map +1 -0
  461. package/dist/registry/entityScanner.js +693 -0
  462. package/dist/registry/entityScanner.js.map +1 -0
  463. package/dist/registry/index.d.ts +9 -0
  464. package/dist/registry/index.d.ts.map +1 -0
  465. package/dist/registry/index.js +13 -0
  466. package/dist/registry/index.js.map +1 -0
  467. package/dist/registry/schema.d.ts +307 -0
  468. package/dist/registry/schema.d.ts.map +1 -0
  469. package/dist/registry/schema.js +139 -0
  470. package/dist/registry/schema.js.map +1 -0
  471. package/dist/registry/sqliteStore.d.ts +101 -0
  472. package/dist/registry/sqliteStore.d.ts.map +1 -0
  473. package/dist/registry/sqliteStore.js +688 -0
  474. package/dist/registry/sqliteStore.js.map +1 -0
  475. package/dist/registry/workItemBridge.d.ts +8 -0
  476. package/dist/registry/workItemBridge.d.ts.map +1 -0
  477. package/dist/registry/workItemBridge.js +30 -0
  478. package/dist/registry/workItemBridge.js.map +1 -0
  479. package/dist/runners/cliRunner.d.ts +11 -0
  480. package/dist/runners/cliRunner.d.ts.map +1 -0
  481. package/dist/runners/cliRunner.js +193 -0
  482. package/dist/runners/cliRunner.js.map +1 -0
  483. package/dist/support/apiCache.d.ts +85 -0
  484. package/dist/support/apiCache.d.ts.map +1 -0
  485. package/dist/support/apiCache.js +163 -0
  486. package/dist/support/apiCache.js.map +1 -0
  487. package/dist/support/chat.d.ts +3 -0
  488. package/dist/support/chat.d.ts.map +1 -0
  489. package/dist/support/chat.js +305 -0
  490. package/dist/support/chat.js.map +1 -0
  491. package/dist/support/chatBackend.d.ts +25 -0
  492. package/dist/support/chatBackend.d.ts.map +1 -0
  493. package/dist/support/chatBackend.js +289 -0
  494. package/dist/support/chatBackend.js.map +1 -0
  495. package/dist/support/chatTui.d.ts +3 -0
  496. package/dist/support/chatTui.d.ts.map +1 -0
  497. package/dist/support/chatTui.js +1082 -0
  498. package/dist/support/chatTui.js.map +1 -0
  499. package/dist/support/costTracker.d.ts +29 -0
  500. package/dist/support/costTracker.d.ts.map +1 -0
  501. package/dist/support/costTracker.js +113 -0
  502. package/dist/support/costTracker.js.map +1 -0
  503. package/dist/support/dashboardHtml.d.ts +5 -0
  504. package/dist/support/dashboardHtml.d.ts.map +1 -0
  505. package/dist/support/dashboardHtml.js +2629 -0
  506. package/dist/support/dashboardHtml.js.map +1 -0
  507. package/dist/support/dev.d.ts +55 -0
  508. package/dist/support/dev.d.ts.map +1 -0
  509. package/dist/support/dev.js +298 -0
  510. package/dist/support/dev.js.map +1 -0
  511. package/dist/support/editParser.d.ts +37 -0
  512. package/dist/support/editParser.d.ts.map +1 -0
  513. package/dist/support/editParser.js +365 -0
  514. package/dist/support/editParser.js.map +1 -0
  515. package/dist/support/ghosttyThemeCatalog.generated.d.ts +2 -0
  516. package/dist/support/ghosttyThemeCatalog.generated.d.ts.map +1 -0
  517. package/dist/support/ghosttyThemeCatalog.generated.js +11116 -0
  518. package/dist/support/ghosttyThemeCatalog.generated.js.map +1 -0
  519. package/dist/support/gitStatus.d.ts +21 -0
  520. package/dist/support/gitStatus.d.ts.map +1 -0
  521. package/dist/support/gitStatus.js +108 -0
  522. package/dist/support/gitStatus.js.map +1 -0
  523. package/dist/support/gitTracker.d.ts +30 -0
  524. package/dist/support/gitTracker.d.ts.map +1 -0
  525. package/dist/support/gitTracker.js +143 -0
  526. package/dist/support/gitTracker.js.map +1 -0
  527. package/dist/support/index.d.ts +12 -0
  528. package/dist/support/index.d.ts.map +1 -0
  529. package/dist/support/index.js +12 -0
  530. package/dist/support/index.js.map +1 -0
  531. package/dist/support/planner.d.ts +64 -0
  532. package/dist/support/planner.d.ts.map +1 -0
  533. package/dist/support/planner.js +396 -0
  534. package/dist/support/planner.js.map +1 -0
  535. package/dist/support/projectMapper.d.ts +46 -0
  536. package/dist/support/projectMapper.d.ts.map +1 -0
  537. package/dist/support/projectMapper.js +273 -0
  538. package/dist/support/projectMapper.js.map +1 -0
  539. package/dist/support/pty-helper.py +117 -0
  540. package/dist/support/quotaTracker.d.ts +29 -0
  541. package/dist/support/quotaTracker.d.ts.map +1 -0
  542. package/dist/support/quotaTracker.js +89 -0
  543. package/dist/support/quotaTracker.js.map +1 -0
  544. package/dist/support/rateLimiter.d.ts +101 -0
  545. package/dist/support/rateLimiter.d.ts.map +1 -0
  546. package/dist/support/rateLimiter.js +219 -0
  547. package/dist/support/rateLimiter.js.map +1 -0
  548. package/dist/support/rollback.d.ts +61 -0
  549. package/dist/support/rollback.d.ts.map +1 -0
  550. package/dist/support/rollback.js +329 -0
  551. package/dist/support/rollback.js.map +1 -0
  552. package/dist/support/sharedShell.d.ts +17 -0
  553. package/dist/support/sharedShell.d.ts.map +1 -0
  554. package/dist/support/sharedShell.js +439 -0
  555. package/dist/support/sharedShell.js.map +1 -0
  556. package/dist/support/stuckDetector.d.ts +68 -0
  557. package/dist/support/stuckDetector.d.ts.map +1 -0
  558. package/dist/support/stuckDetector.js +174 -0
  559. package/dist/support/stuckDetector.js.map +1 -0
  560. package/dist/support/terminalBridge.d.ts +18 -0
  561. package/dist/support/terminalBridge.d.ts.map +1 -0
  562. package/dist/support/terminalBridge.js +553 -0
  563. package/dist/support/terminalBridge.js.map +1 -0
  564. package/dist/support/timeWindow.d.ts +60 -0
  565. package/dist/support/timeWindow.d.ts.map +1 -0
  566. package/dist/support/timeWindow.js +236 -0
  567. package/dist/support/timeWindow.js.map +1 -0
  568. package/dist/support/uiThemes.d.ts +44 -0
  569. package/dist/support/uiThemes.d.ts.map +1 -0
  570. package/dist/support/uiThemes.js +290 -0
  571. package/dist/support/uiThemes.js.map +1 -0
  572. package/dist/support/web.d.ts +29 -0
  573. package/dist/support/web.d.ts.map +1 -0
  574. package/dist/support/web.js +1097 -0
  575. package/dist/support/web.js.map +1 -0
  576. package/dist/support/worktreeManager.d.ts +20 -0
  577. package/dist/support/worktreeManager.d.ts.map +1 -0
  578. package/dist/support/worktreeManager.js +140 -0
  579. package/dist/support/worktreeManager.js.map +1 -0
  580. package/dist/task_state_model.py +55 -0
  581. package/dist/workItemState/store.d.ts +122 -0
  582. package/dist/workItemState/store.d.ts.map +1 -0
  583. package/dist/workItemState/store.js +438 -0
  584. package/dist/workItemState/store.js.map +1 -0
  585. package/dist/workItems/azdoBridge.d.ts +42 -0
  586. package/dist/workItems/azdoBridge.d.ts.map +1 -0
  587. package/dist/workItems/azdoBridge.js +143 -0
  588. package/dist/workItems/azdoBridge.js.map +1 -0
  589. package/dist/workItems/azdoSyncRuntime.d.ts +28 -0
  590. package/dist/workItems/azdoSyncRuntime.d.ts.map +1 -0
  591. package/dist/workItems/azdoSyncRuntime.js +158 -0
  592. package/dist/workItems/azdoSyncRuntime.js.map +1 -0
  593. package/dist/workItems/azureDevOpsSync.d.ts +128 -0
  594. package/dist/workItems/azureDevOpsSync.d.ts.map +1 -0
  595. package/dist/workItems/azureDevOpsSync.js +748 -0
  596. package/dist/workItems/azureDevOpsSync.js.map +1 -0
  597. package/dist/workItems/helpers.d.ts +11 -0
  598. package/dist/workItems/helpers.d.ts.map +1 -0
  599. package/dist/workItems/helpers.js +17 -0
  600. package/dist/workItems/helpers.js.map +1 -0
  601. package/dist/workItems/index.d.ts +21 -0
  602. package/dist/workItems/index.d.ts.map +1 -0
  603. package/dist/workItems/index.js +89 -0
  604. package/dist/workItems/index.js.map +1 -0
  605. package/dist/workItems/localWorkItemFetcher.d.ts +55 -0
  606. package/dist/workItems/localWorkItemFetcher.d.ts.map +1 -0
  607. package/dist/workItems/localWorkItemFetcher.js +209 -0
  608. package/dist/workItems/localWorkItemFetcher.js.map +1 -0
  609. package/dist/workItems/migrations/001_rename_workItem_to_work_item.sql +10 -0
  610. package/dist/workItems/postgresStore.d.ts +78 -0
  611. package/dist/workItems/postgresStore.d.ts.map +1 -0
  612. package/dist/workItems/postgresStore.js +937 -0
  613. package/dist/workItems/postgresStore.js.map +1 -0
  614. package/dist/workItems/schema.d.ts +257 -0
  615. package/dist/workItems/schema.d.ts.map +1 -0
  616. package/dist/workItems/schema.js +176 -0
  617. package/dist/workItems/schema.js.map +1 -0
  618. package/dist/workItems/sqliteStore.d.ts +124 -0
  619. package/dist/workItems/sqliteStore.d.ts.map +1 -0
  620. package/dist/workItems/sqliteStore.js +713 -0
  621. package/dist/workItems/sqliteStore.js.map +1 -0
  622. package/dist/workItems/workItemBoardHtml.d.ts +5 -0
  623. package/dist/workItems/workItemBoardHtml.d.ts.map +1 -0
  624. package/dist/workItems/workItemBoardHtml.js +2192 -0
  625. package/dist/workItems/workItemBoardHtml.js.map +1 -0
  626. package/package.json +99 -0
  627. package/templates/AGENTS.md +432 -0
  628. package/templates/BOOT.md +25 -0
  629. package/templates/BOOTSTRAP.md +50 -0
  630. package/templates/CHANGELOG_AUDIT.md +74 -0
  631. package/templates/HEARTBEAT.md +86 -0
  632. package/templates/IDENTITY.md +27 -0
  633. package/templates/PR_LAND.md +75 -0
  634. package/templates/PR_REVIEW.md +97 -0
  635. package/templates/SOUL.dev.md +52 -0
  636. package/templates/SOUL.md +81 -0
  637. package/templates/TOOLS.md +52 -0
  638. package/templates/USER.md +22 -0
  639. package/templates/WORKITEM_ANALYSIS.md +31 -0
  640. package/templates/agents/executor.md +26 -0
  641. package/templates/agents/plan.md +22 -0
  642. package/templates/agents/ralph.md +37 -0
  643. package/templates/agents/review.md +22 -0
  644. package/templates/agents/team.md +39 -0
@@ -0,0 +1,1082 @@
1
+ #!/usr/bin/env tsx
2
+ // EnactFactory - Rich TUI Chat Interface
3
+ // Claude Code style tabbed interface with real-time updates
4
+ import blessed from 'blessed';
5
+ import { resolve } from 'node:path';
6
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
7
+ import { existsSync } from 'node:fs';
8
+ import { getDefaultAdapterName } from '../adapters/index.js';
9
+ import { getDefaultChatModel, resolveChatModel, runChatCompletion, shortenChatModel } from '../support/chatBackend.js';
10
+ import { sessionsPath } from '../factory/paths.js';
11
+ import { requireWorkspaceUiPort } from '../core/workspaceConfig.js';
12
+ // Constants
13
+ const CHAT_DIR = sessionsPath('chat');
14
+ const FACTORY_DASHBOARD_PORT = String(requireWorkspaceUiPort());
15
+ const FACTORY_DASHBOARD_BASE_URL = `http://127.0.0.1:${FACTORY_DASHBOARD_PORT}`;
16
+ // Render guard: blessed는 동시 render() 호출 시 화면이 검은색으로 깨질 수 있음
17
+ let renderScheduled = false;
18
+ let screenRef = null;
19
+ function safeRender() {
20
+ if (renderScheduled || !screenRef)
21
+ return;
22
+ renderScheduled = true;
23
+ process.nextTick(() => {
24
+ renderScheduled = false;
25
+ try {
26
+ screenRef.render();
27
+ }
28
+ catch {
29
+ // render 실패 시 복구 시도
30
+ try {
31
+ screenRef.alloc();
32
+ screenRef.render();
33
+ }
34
+ catch {
35
+ // 무시 — 다음 사이클에서 복구
36
+ }
37
+ }
38
+ });
39
+ }
40
+ // Session Management
41
+ async function ensureChatDir() {
42
+ await mkdir(CHAT_DIR, { recursive: true });
43
+ }
44
+ async function saveSession(session) {
45
+ await ensureChatDir();
46
+ session.updatedAt = new Date().toISOString();
47
+ const path = resolve(CHAT_DIR, `${session.id}.json`);
48
+ await writeFile(path, JSON.stringify(session, null, 2));
49
+ }
50
+ async function loadSession(id) {
51
+ const path = resolve(CHAT_DIR, `${id}.json`);
52
+ if (!existsSync(path))
53
+ return null;
54
+ const data = JSON.parse(await readFile(path, 'utf-8'));
55
+ const provider = data.provider ?? inferProvider(undefined, data.model);
56
+ return {
57
+ ...data,
58
+ provider,
59
+ model: data.model ?? getDefaultChatModel(provider),
60
+ totalCost: data.totalCost ?? 0,
61
+ totalTokens: data.totalTokens ?? 0,
62
+ };
63
+ }
64
+ function generateSessionId() {
65
+ const now = new Date();
66
+ const pad = (n) => String(n).padStart(2, '0');
67
+ return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}`;
68
+ }
69
+ function inferProvider(provider, model) {
70
+ if (provider)
71
+ return provider;
72
+ if (model?.includes('codex'))
73
+ return 'codex';
74
+ if (model?.startsWith('gpt-') || model?.startsWith('o3') || model?.startsWith('o4'))
75
+ return 'responses';
76
+ return loadDefaultProvider();
77
+ }
78
+ function loadDefaultProvider() {
79
+ return getDefaultAdapterName();
80
+ }
81
+ // Shared chat backend
82
+ async function callChatModel(prompt, provider, model, sessionId, onStream) {
83
+ const result = await runChatCompletion({
84
+ prompt,
85
+ provider,
86
+ model,
87
+ sessionId: provider === 'claude' ? sessionId : undefined,
88
+ timeoutMs: 180000,
89
+ onText: onStream,
90
+ });
91
+ return {
92
+ response: result.response,
93
+ sessionId: result.sessionId ?? '',
94
+ cost: result.cost ?? 0,
95
+ tokens: result.tokens ?? 0,
96
+ };
97
+ }
98
+ // Warhammer 40k Loading Messages
99
+ const LOADING_MESSAGES = [
100
+ 'Initializing cogitator arrays',
101
+ 'Querying data-vault archives',
102
+ 'Accessing servitor protocols',
103
+ 'Compiling neural responses',
104
+ 'Interfacing with the Noosphere',
105
+ 'Scanning data-streams',
106
+ 'Calibrating logic engines',
107
+ 'Decoding transmission packets',
108
+ 'Loading archive databases',
109
+ 'Synchronizing machine protocols',
110
+ 'Analyzing pattern matrices',
111
+ 'Establishing neural link',
112
+ 'Processing data-core output',
113
+ 'Running diagnostics sequence',
114
+ 'Activating response circuits',
115
+ ];
116
+ const SPINNER_FRAMES = ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'];
117
+ // UI Components - Claude Code Style
118
+ function createUI() {
119
+ const screen = blessed.screen({
120
+ smartCSR: true,
121
+ title: 'Enact Factory Chat',
122
+ fullUnicode: true,
123
+ terminal: 'xterm-256color',
124
+ forceUnicode: true,
125
+ warnings: false, // Suppress warnings that can corrupt display
126
+ dockBorders: true, // Better border handling in tmux
127
+ fastCSR: true, // Faster rendering for streaming
128
+ });
129
+ const colors = {
130
+ bg: '#1a1a1a',
131
+ statusBg: '#2d3748',
132
+ statusFg: '#e2e8f0',
133
+ tabActiveBg: '#4a5568',
134
+ tabActiveFg: '#f7fafc',
135
+ tabInactiveBg: '#2d3748',
136
+ tabInactiveFg: '#a0aec0',
137
+ border: '#4a5568',
138
+ borderActive: '#667eea',
139
+ inputBorder: '#48bb78',
140
+ scrollbar: '#4a5568',
141
+ userMessage: '#60a5fa',
142
+ assistantMessage: '#34d399',
143
+ dimText: '#718096',
144
+ };
145
+ const statusBar = blessed.box({
146
+ top: 0,
147
+ left: 0,
148
+ width: '100%',
149
+ height: 1,
150
+ tags: true,
151
+ style: {
152
+ fg: colors.statusFg,
153
+ bg: colors.statusBg,
154
+ },
155
+ });
156
+ const tabBar = blessed.box({
157
+ top: 1,
158
+ left: 0,
159
+ width: '100%',
160
+ height: 1,
161
+ tags: true,
162
+ style: {
163
+ fg: colors.tabInactiveFg,
164
+ bg: colors.tabInactiveBg,
165
+ },
166
+ });
167
+ // Chat tab content - clean borders (adjusted for taller input box)
168
+ const chatLog = blessed.log({
169
+ top: 2,
170
+ left: 0,
171
+ width: '100%',
172
+ height: '100%-9', // Increased from -7 to -9 for 5-line input box
173
+ scrollable: true,
174
+ alwaysScroll: true,
175
+ mouse: true,
176
+ scrollbar: {
177
+ ch: '│',
178
+ track: {
179
+ bg: '#1a1a1a',
180
+ },
181
+ style: {
182
+ fg: colors.scrollbar,
183
+ },
184
+ },
185
+ tags: true,
186
+ border: { type: 'line' },
187
+ style: {
188
+ fg: '#e2e8f0',
189
+ bg: '#1a1a1a',
190
+ border: {
191
+ fg: colors.border,
192
+ },
193
+ },
194
+ });
195
+ const projectsBox = blessed.box({
196
+ top: 2,
197
+ left: 0,
198
+ width: '100%',
199
+ height: '100%-9', // Adjusted for taller input box
200
+ content: '{center}{#718096-fg}Loading projects...{/}{/center}',
201
+ tags: true,
202
+ scrollable: true,
203
+ mouse: true,
204
+ scrollbar: {
205
+ ch: '│',
206
+ style: { fg: colors.scrollbar },
207
+ },
208
+ border: { type: 'line' },
209
+ style: {
210
+ fg: '#e2e8f0',
211
+ bg: '#1a1a1a',
212
+ border: { fg: colors.border },
213
+ },
214
+ hidden: true,
215
+ });
216
+ const pipelineBox = blessed.box({
217
+ top: 2,
218
+ left: 0,
219
+ width: '100%',
220
+ height: '100%-9', // Adjusted for taller input box
221
+ content: '{center}{#718096-fg}Loading workItems...{/}{/center}',
222
+ tags: true,
223
+ scrollable: true,
224
+ mouse: true,
225
+ scrollbar: {
226
+ ch: '│',
227
+ style: { fg: colors.scrollbar },
228
+ },
229
+ border: { type: 'line' },
230
+ style: {
231
+ fg: '#e2e8f0',
232
+ bg: '#1a1a1a',
233
+ border: { fg: colors.border },
234
+ },
235
+ hidden: true,
236
+ });
237
+ const stuckBox = blessed.box({
238
+ top: 2,
239
+ left: 0,
240
+ width: '100%',
241
+ height: '100%-9',
242
+ content: '{center}{#718096-fg}Loading stuck work items...{/}{/center}',
243
+ tags: true,
244
+ scrollable: true,
245
+ alwaysScroll: true,
246
+ mouse: true,
247
+ keys: true,
248
+ vi: true,
249
+ scrollbar: {
250
+ ch: '█',
251
+ style: { fg: colors.scrollbar },
252
+ },
253
+ style: {
254
+ border: { fg: colors.border },
255
+ },
256
+ hidden: true,
257
+ });
258
+ const logsBox = blessed.log({
259
+ top: 2,
260
+ left: 0,
261
+ width: '100%',
262
+ height: '100%-9', // Adjusted for taller input box
263
+ scrollable: true,
264
+ alwaysScroll: true,
265
+ mouse: true,
266
+ scrollbar: {
267
+ ch: '│',
268
+ style: { fg: colors.scrollbar },
269
+ },
270
+ tags: true,
271
+ border: { type: 'line' },
272
+ style: {
273
+ fg: '#e2e8f0',
274
+ bg: '#1a1a1a',
275
+ border: { fg: colors.border },
276
+ },
277
+ hidden: true,
278
+ });
279
+ const workItemsBox = blessed.box({
280
+ top: 2,
281
+ left: 0,
282
+ width: '100%',
283
+ height: '100%-9',
284
+ scrollable: true,
285
+ alwaysScroll: true,
286
+ mouse: true,
287
+ scrollbar: {
288
+ ch: '│',
289
+ style: { fg: colors.scrollbar },
290
+ },
291
+ tags: true,
292
+ border: { type: 'line' },
293
+ label: ' {#00ccdd-fg}WorkItems{/} ',
294
+ style: {
295
+ border: { fg: colors.border },
296
+ },
297
+ hidden: true,
298
+ });
299
+ // Input box - textarea for multiline + Korean support
300
+ const inputBox = blessed.textarea({
301
+ bottom: 1,
302
+ left: 0,
303
+ width: '100%',
304
+ height: 5, // Increased height for multiline
305
+ inputOnFocus: true,
306
+ border: { type: 'line' },
307
+ label: ' {#718096-fg}Message (Shift+Enter: newline, Enter: send){/} ',
308
+ tags: true,
309
+ keys: true, // Enable key handling
310
+ mouse: true,
311
+ scrollable: true,
312
+ alwaysScroll: false,
313
+ style: {
314
+ fg: '#f7fafc',
315
+ bg: '#1a1a1a',
316
+ border: { fg: colors.border },
317
+ focus: {
318
+ border: { fg: colors.borderActive },
319
+ bg: '#0d1117',
320
+ },
321
+ },
322
+ });
323
+ const helpBar = blessed.box({
324
+ bottom: 0,
325
+ left: 0,
326
+ width: '100%',
327
+ height: 1,
328
+ content: ' {#718096-fg}Tab{/} Switch {#718096-fg}Enter{/} Send {#718096-fg}Shift+Enter{/} Newline {#718096-fg}Esc{/} Exit Input {#718096-fg}i{/} Focus Input {#718096-fg}Ctrl+C{/} Exit {#718096-fg}/help{/} Cmds',
329
+ tags: true,
330
+ style: {
331
+ fg: '#a0aec0',
332
+ bg: colors.statusBg,
333
+ },
334
+ });
335
+ screen.append(statusBar);
336
+ screen.append(tabBar);
337
+ screen.append(chatLog);
338
+ screen.append(projectsBox);
339
+ screen.append(pipelineBox);
340
+ screen.append(stuckBox);
341
+ screen.append(logsBox);
342
+ screen.append(workItemsBox);
343
+ screen.append(inputBox);
344
+ screen.append(helpBar);
345
+ return {
346
+ screen,
347
+ statusBar,
348
+ tabBar,
349
+ chatLog,
350
+ projectsBox,
351
+ pipelineBox,
352
+ workItemsBox,
353
+ stuckBox,
354
+ logsBox,
355
+ inputBox,
356
+ helpBar,
357
+ };
358
+ }
359
+ // Tab Management
360
+ function updateTabBar(ui, currentTab) {
361
+ const tabs = [
362
+ { key: '1', name: 'Chat', icon: '💬' },
363
+ { key: '2', name: 'Projects', icon: '📁' },
364
+ { key: '3', name: 'Pipeline', icon: '✓' },
365
+ { key: '4', name: 'Stuck', icon: '⚠' },
366
+ { key: '5', name: 'WorkItems', icon: '🎫' },
367
+ { key: '6', name: 'Logs', icon: '📝' },
368
+ ];
369
+ const content = tabs.map((tab, idx) => {
370
+ if (idx === currentTab) {
371
+ // Active tab - highlighted
372
+ return `{#4a5568-bg}{#f7fafc-fg}{bold} ${tab.icon} ${tab.name} {/bold}{/}{/}`;
373
+ }
374
+ // Inactive tab - dimmed
375
+ return `{#2d3748-bg}{#a0aec0-fg} ${tab.icon} ${tab.name} {/}{/}`;
376
+ }).join(' ');
377
+ ui.tabBar.setContent(' ' + content);
378
+ }
379
+ function switchTab(state, ui, tabIndex) {
380
+ state.currentTab = tabIndex;
381
+ ui.chatLog.hide();
382
+ ui.projectsBox.hide();
383
+ ui.pipelineBox.hide();
384
+ ui.workItemsBox.hide();
385
+ ui.stuckBox.hide();
386
+ ui.logsBox.hide();
387
+ switch (tabIndex) {
388
+ case 0:
389
+ ui.chatLog.show();
390
+ break;
391
+ case 1:
392
+ ui.projectsBox.show();
393
+ loadProjectsData(ui.projectsBox);
394
+ break;
395
+ case 2:
396
+ ui.pipelineBox.show();
397
+ loadPipelineData(ui.pipelineBox);
398
+ break;
399
+ case 3:
400
+ ui.stuckBox.show();
401
+ loadStuckData(ui.stuckBox);
402
+ break;
403
+ case 4:
404
+ ui.workItemsBox.show();
405
+ loadWorkItemsData(ui.workItemsBox);
406
+ break;
407
+ case 5:
408
+ ui.logsBox.show();
409
+ break;
410
+ }
411
+ updateTabBar(ui, tabIndex);
412
+ safeRender();
413
+ }
414
+ // Data Loaders
415
+ async function loadProjectsData(box) {
416
+ try {
417
+ const response = await fetch(`${FACTORY_DASHBOARD_BASE_URL}/api/projects`);
418
+ const projects = await response.json();
419
+ if (projects.length === 0) {
420
+ box.setContent('\n{center}{#718096-fg}No projects tracked{/}{/center}');
421
+ return;
422
+ }
423
+ const lines = [
424
+ '',
425
+ ` {#a0aec0-fg}${projects.length} project${projects.length > 1 ? 's' : ''} tracked{/}`,
426
+ '',
427
+ ];
428
+ for (const p of projects) {
429
+ const status = p.enabled ? '{#34d399-fg}●{/}' : '{#718096-fg}○{/}';
430
+ const running = p.running.length > 0 ? `{#60a5fa-fg}${p.running.length} running{/}` : '';
431
+ const queued = p.queued.length > 0 ? `{#f59e0b-fg}${p.queued.length} queued{/}` : '';
432
+ const workItems = [running, queued].filter(Boolean).join(' · ');
433
+ lines.push(` ${status} {bold}${p.name}{/bold}`);
434
+ if (workItems) {
435
+ lines.push(` ${workItems}`);
436
+ }
437
+ lines.push(` {#718096-fg}${p.path}{/}`);
438
+ lines.push('');
439
+ }
440
+ box.setContent(lines.join('\n'));
441
+ }
442
+ catch (err) {
443
+ box.setContent(`\n{center}{#ef4444-fg}Failed to load projects{/}\n{#718096-fg}${err}{/}{/center}`);
444
+ }
445
+ }
446
+ async function loadPipelineData(box) {
447
+ try {
448
+ const response = await fetch(`${FACTORY_DASHBOARD_BASE_URL}/api/pipeline`);
449
+ const { stages } = await response.json();
450
+ if (stages.length === 0) {
451
+ box.setContent('\n{center}{#718096-fg}No pipeline events{/}{/center}');
452
+ return;
453
+ }
454
+ // Build workItem info map and extract stage events
455
+ const workItemInfo = new Map();
456
+ const allStageEvents = [];
457
+ for (const event of stages) {
458
+ if (event.type === 'workItem:started' && event.data.workItemId) {
459
+ workItemInfo.set(event.data.workItemId, { title: event.data.title, workItemIdentifier: event.data.workItemIdentifier });
460
+ }
461
+ else if (event.type === 'pipeline:stage' && event.data.workItemId && event.data.stage) {
462
+ allStageEvents.push({
463
+ workItemId: event.data.workItemId,
464
+ stage: event.data.stage,
465
+ status: event.data.status || '',
466
+ model: event.data.model,
467
+ inputTokens: event.data.inputTokens,
468
+ outputTokens: event.data.outputTokens,
469
+ costUsd: event.data.costUsd,
470
+ });
471
+ }
472
+ }
473
+ if (allStageEvents.length === 0) {
474
+ box.setContent('\n{center}{#718096-fg}No active pipeline stages{/}{/center}');
475
+ return;
476
+ }
477
+ // Render pipeline table
478
+ const recentStages = allStageEvents.slice(-15).reverse();
479
+ const lines = [
480
+ '',
481
+ ` {#34d399-fg}{bold}Pipeline Events{/bold} {#718096-fg}(${recentStages.length} recent){/}{/}`,
482
+ '',
483
+ ` {#718096-fg}${'WORKITEM'.padEnd(12)} ${'STAGE'.padEnd(10)} ${'MODEL'.padEnd(12)} ${'TOKENS'.padEnd(15)} STATUS{/}`,
484
+ ` {#444444-fg}${'─'.repeat(70)}{/}`,
485
+ ];
486
+ for (const ev of recentStages) {
487
+ const info = workItemInfo.get(ev.workItemId);
488
+ const workItem = (info?.workItemIdentifier || ev.workItemId.slice(0, 8)).padEnd(12).slice(0, 12);
489
+ const stage = ev.stage.padEnd(10).slice(0, 10);
490
+ const statusMap = {
491
+ start: ['◐', '#f59e0b'],
492
+ complete: ['●', '#34d399'],
493
+ fail: ['✗', '#ef4444'],
494
+ };
495
+ const [icon, color] = statusMap[ev.status] || ['○', '#718096'];
496
+ let model = '';
497
+ if (ev.model?.includes('sonnet-4-5'))
498
+ model = 'sonnet-4.5';
499
+ else if (ev.model?.includes('haiku-4-5'))
500
+ model = 'haiku-4.5';
501
+ else if (ev.model?.includes('opus-4'))
502
+ model = 'opus-4';
503
+ else if (ev.model)
504
+ model = ev.model.split('-').pop() || '';
505
+ model = model.padEnd(12).slice(0, 12);
506
+ let tokens = '';
507
+ if (ev.inputTokens || ev.outputTokens) {
508
+ const inK = ev.inputTokens ? Math.round(ev.inputTokens / 1000) : 0;
509
+ const outK = ev.outputTokens ? Math.round(ev.outputTokens / 1000) : 0;
510
+ tokens = `${inK}k/${outK}k`;
511
+ if (ev.costUsd != null)
512
+ tokens += ` $${ev.costUsd.toFixed(2)}`;
513
+ }
514
+ tokens = tokens.padEnd(15).slice(0, 15);
515
+ lines.push(` {#34d399-fg}${workItem}{/} {#718096-fg}${stage}{/} {#34d399-fg}${model}{/} {#718096-fg}${tokens}{/} {${color}-fg}${icon} ${ev.status}{/}`);
516
+ }
517
+ box.setContent(lines.join('\n'));
518
+ }
519
+ catch (err) {
520
+ box.setContent(`\n{center}{#ef4444-fg}Failed to load pipeline{/}\n{#718096-fg}${err}{/}{/center}`);
521
+ }
522
+ }
523
+ async function loadStuckData(box) {
524
+ try {
525
+ const response = await fetch(`${FACTORY_DASHBOARD_BASE_URL}/api/workitems/stuck`);
526
+ const { stuckWorkItems, failedWorkItems } = await response.json();
527
+ const totalStuck = stuckWorkItems.length;
528
+ const totalFailed = failedWorkItems.length;
529
+ const total = totalStuck + totalFailed;
530
+ if (total === 0) {
531
+ box.setContent('\n{center}{#34d399-fg}✓ All work items healthy{/}{/center}');
532
+ return;
533
+ }
534
+ const lines = [
535
+ '',
536
+ ` {#ef4444-fg}⚠ ${total} work item${total > 1 ? 's' : ''} need attention{/}`,
537
+ '',
538
+ ];
539
+ // Stuck work items
540
+ if (totalStuck > 0) {
541
+ lines.push(` {#f59e0b-fg}{bold}⏱ STUCK (${totalStuck}){/bold}{/}`);
542
+ lines.push('');
543
+ for (const workItem of stuckWorkItems) {
544
+ const priorityIcon = workItem.priority === 1 ? '{#ef4444-fg}🔴{/}' : workItem.priority === 2 ? '{#f59e0b-fg}🟡{/}' : '{#718096-fg}⚪{/}';
545
+ lines.push(` ${priorityIcon} {bold}${workItem.identifier}{/bold}`);
546
+ lines.push(` ${workItem.title.substring(0, 60)}${workItem.title.length > 60 ? '...' : ''}`);
547
+ lines.push(` {#f59e0b-fg}${workItem.reason}{/}`);
548
+ if (workItem.project?.name) {
549
+ lines.push(` {#718096-fg}📁 ${workItem.project.name}{/}`);
550
+ }
551
+ lines.push('');
552
+ }
553
+ }
554
+ // Failed work items
555
+ if (totalFailed > 0) {
556
+ lines.push(` {#ef4444-fg}{bold}✖ FAILED (${totalFailed}){/bold}{/}`);
557
+ lines.push('');
558
+ for (const workItem of failedWorkItems) {
559
+ const priorityIcon = workItem.priority === 1 ? '{#ef4444-fg}🔴{/}' : workItem.priority === 2 ? '{#f59e0b-fg}🟡{/}' : '{#718096-fg}⚪{/}';
560
+ lines.push(` ${priorityIcon} {bold}${workItem.identifier}{/bold}`);
561
+ lines.push(` ${workItem.title.substring(0, 60)}${workItem.title.length > 60 ? '...' : ''}`);
562
+ lines.push(` {#ef4444-fg}${workItem.reason}{/}`);
563
+ if (workItem.project?.name) {
564
+ lines.push(` {#718096-fg}📁 ${workItem.project.name}{/}`);
565
+ }
566
+ lines.push('');
567
+ }
568
+ }
569
+ box.setContent(lines.join('\n'));
570
+ }
571
+ catch (err) {
572
+ box.setContent(`\n{center}{#ef4444-fg}Failed to load stuck work items{/}\n{#718096-fg}${err}{/}{/center}`);
573
+ }
574
+ }
575
+ // WorkItems Data Loader (로컬 이슈 트래커)
576
+ async function loadWorkItemsData(box) {
577
+ try {
578
+ const response = await fetch(`${FACTORY_DASHBOARD_BASE_URL}/api/factory/workitems`);
579
+ const json = await response.json();
580
+ if (!json.ok)
581
+ throw new Error('Work-items endpoint returned ok:false');
582
+ const items = json.data;
583
+ const total = json.total;
584
+ if (total === 0) {
585
+ box.setContent(`\n{center}{#718096-fg}No work items tracked{/}\n\n{#445544-fg}Create work items via web dashboard (:${FACTORY_DASHBOARD_PORT}/workitems){/}{/center}`);
586
+ return;
587
+ }
588
+ const lines = [
589
+ '',
590
+ ` {#00ccdd-fg}{bold}🎫 WORK ITEMS{/bold}{/} — total: {bold}${total}{/bold}`,
591
+ '',
592
+ ];
593
+ lines.push(' ' + '─'.repeat(70));
594
+ lines.push('');
595
+ const priorityIcons = {
596
+ urgent: '{#ef4444-fg}●{/}', high: '{#ffaa00-fg}●{/}',
597
+ medium: '{#00ccdd-fg}●{/}', low: '{#718096-fg}●{/}', none: '{#445544-fg}○{/}',
598
+ };
599
+ const statusColors = {
600
+ backlog: '#718096', todo: '#e2e8f0', in_progress: '#ffaa00',
601
+ in_review: '#00ccdd', done: '#00ff41', cancelled: '#ef4444',
602
+ };
603
+ for (const iss of items.slice(0, 50)) {
604
+ const priority = iss.layeredState?.business?.priority ?? 'none';
605
+ const status = iss.layeredState?.business?.state ?? iss.status ?? 'backlog';
606
+ const icon = priorityIcons[priority] || '{#718096-fg}●{/}';
607
+ const stColor = statusColors[status] || '#718096';
608
+ const title = iss.title.length > 50 ? iss.title.substring(0, 50) + '...' : iss.title;
609
+ const labels = (iss.labels || []).slice(0, 2).map((l) => `{#445544-fg}[${l}]{/}`).join('');
610
+ lines.push(` ${icon} {${stColor}-fg}${String(status).padEnd(12)}{/} {bold}${title}{/bold}`);
611
+ lines.push(` {#718096-fg}${iss.id.slice(0, 6)} | ${iss.area ?? iss.projectId ?? ''}${iss.assignee ? ' | ' + iss.assignee : ''}{/} ${labels}`);
612
+ lines.push('');
613
+ }
614
+ if (total > 50) {
615
+ lines.push(` {#718096-fg}... and ${total - 50} more work items{/}`);
616
+ }
617
+ lines.push('');
618
+ lines.push(` {#445544-fg}Open web dashboard for full management: http://localhost:${FACTORY_DASHBOARD_PORT}/workitems{/}`);
619
+ box.setContent(lines.join('\n'));
620
+ }
621
+ catch (err) {
622
+ box.setContent(`\n{center}{#ef4444-fg}Failed to load work items{/}\n{#718096-fg}${err}{/}\n\n{#445544-fg}Make sure the service is running{/}{/center}`);
623
+ }
624
+ }
625
+ // Loading Spinner (inline in chat)
626
+ function startSpinner(ui) {
627
+ let frameIndex = 0;
628
+ const loadingMessage = LOADING_MESSAGES[Math.floor(Math.random() * LOADING_MESSAGES.length)];
629
+ const lines = ui.chatLog.getLines();
630
+ const lineIndex = lines.length;
631
+ const interval = setInterval(() => {
632
+ const spinner = SPINNER_FRAMES[frameIndex % SPINNER_FRAMES.length];
633
+ const content = ` {#667eea-fg}${spinner}{/} {#718096-fg}${loadingMessage}...{/}`;
634
+ ui.chatLog.setLine(lineIndex, content);
635
+ ui.chatLog.setScrollPerc(100);
636
+ safeRender();
637
+ frameIndex++;
638
+ }, 80);
639
+ return { interval, lineIndex };
640
+ }
641
+ function stopSpinner(ui, spinnerData) {
642
+ clearInterval(spinnerData.interval);
643
+ ui.chatLog.deleteLine(spinnerData.lineIndex);
644
+ safeRender();
645
+ }
646
+ // Chat Logic
647
+ async function sendMessage(state, ui, message) {
648
+ if (!message.trim())
649
+ return;
650
+ ui.chatLog.log('');
651
+ ui.chatLog.log(`{#60a5fa-fg}{bold}▸ You{/bold}{/}`);
652
+ ui.chatLog.log(` ${message}`);
653
+ ui.chatLog.log('');
654
+ ui.chatLog.setScrollPerc(100);
655
+ safeRender();
656
+ state.session.messages.push({ role: 'user', content: message });
657
+ ui.chatLog.log(`{#34d399-fg}{bold}▸ Assistant{/bold}{/}`);
658
+ const assistantHeaderLine = ui.chatLog.getLines().length - 1;
659
+ let assistantContent = '';
660
+ let lastRenderTime = 0;
661
+ let spinnerStopped = false;
662
+ let contentStartLine = assistantHeaderLine + 1;
663
+ const spinnerData = startSpinner(ui);
664
+ try {
665
+ const result = await callChatModel(message, state.session.provider, state.session.model, state.session.claudeSessionId, (chunk, isThinking) => {
666
+ // Handle thinking notification (show/resume spinner)
667
+ if (isThinking) {
668
+ if (spinnerStopped) {
669
+ // Resume spinner for thinking phase
670
+ spinnerStopped = false;
671
+ const newSpinner = startSpinner(ui);
672
+ Object.assign(spinnerData, newSpinner);
673
+ }
674
+ return;
675
+ }
676
+ // Stop spinner on first text chunk
677
+ if (!spinnerStopped && chunk) {
678
+ stopSpinner(ui, spinnerData);
679
+ spinnerStopped = true;
680
+ }
681
+ if (!chunk)
682
+ return;
683
+ assistantContent += chunk;
684
+ // Throttle rendering for smoother streaming (30fps)
685
+ const now = Date.now();
686
+ if (now - lastRenderTime < 33)
687
+ return;
688
+ lastRenderTime = now;
689
+ // Clear previous content lines (안전한 역순 삭제)
690
+ const currentLines = ui.chatLog.getLines().length;
691
+ const deleteCount = Math.max(0, Math.min(currentLines - contentStartLine, currentLines));
692
+ for (let i = 0; i < deleteCount; i++) {
693
+ ui.chatLog.deleteLine(contentStartLine);
694
+ }
695
+ // Add updated content line by line with proper empty line handling
696
+ const contentLines = assistantContent.split('\n');
697
+ for (const line of contentLines) {
698
+ // Always add line, even if empty (preserves paragraph breaks)
699
+ ui.chatLog.log(line ? ` ${line}` : ' ');
700
+ }
701
+ ui.chatLog.setScrollPerc(100);
702
+ safeRender();
703
+ });
704
+ // Ensure spinner is stopped
705
+ if (!spinnerStopped) {
706
+ stopSpinner(ui, spinnerData);
707
+ spinnerStopped = true;
708
+ }
709
+ if (state.session.provider === 'claude' && result.sessionId) {
710
+ state.session.claudeSessionId = result.sessionId;
711
+ }
712
+ // Update session stats
713
+ state.session.totalCost += result.cost;
714
+ state.session.totalTokens += result.tokens;
715
+ // Finalize assistant message with cost
716
+ // Clear streaming content first (안전한 삭제)
717
+ const finalLines = ui.chatLog.getLines().length;
718
+ const finalDeleteCount = Math.max(0, Math.min(finalLines - contentStartLine, finalLines));
719
+ for (let i = 0; i < finalDeleteCount; i++) {
720
+ ui.chatLog.deleteLine(contentStartLine);
721
+ }
722
+ // Add final content line by line with proper empty line handling
723
+ const contentLines = result.response.split('\n');
724
+ for (const line of contentLines) {
725
+ // Always add line, even if empty (preserves paragraph breaks)
726
+ ui.chatLog.log(line ? ` ${line}` : ' ');
727
+ }
728
+ // Add cost info if available
729
+ if (result.cost > 0) {
730
+ ui.chatLog.log(` {#718096-fg}${result.tokens} tokens · $${result.cost.toFixed(4)}{/}`);
731
+ }
732
+ ui.chatLog.log('');
733
+ state.session.messages.push({
734
+ role: 'assistant',
735
+ content: result.response,
736
+ cost: result.cost,
737
+ });
738
+ await saveSession(state.session);
739
+ updateStatusBar(state, ui);
740
+ safeRender();
741
+ }
742
+ catch (err) {
743
+ if (!spinnerStopped) {
744
+ stopSpinner(ui, spinnerData);
745
+ }
746
+ const msg = err instanceof Error ? err.message : String(err);
747
+ ui.chatLog.log(`{#ef4444-fg}{bold}✗ Error{/bold}{/}`);
748
+ ui.chatLog.log(` ${msg}`);
749
+ ui.chatLog.log('');
750
+ state.session.messages.pop(); // Remove user message on failure
751
+ safeRender();
752
+ }
753
+ }
754
+ // Status Bar Update
755
+ function updateStatusBar(state, ui) {
756
+ const modelShort = shortenChatModel(state.session.model);
757
+ const cost = state.session.totalCost > 0 ? `$${state.session.totalCost.toFixed(4)}` : '$0.00';
758
+ const msgs = state.session.messages.length;
759
+ const status = [
760
+ '{bold}Enact Factory{/bold}',
761
+ `{#718096-fg}│{/}`,
762
+ `{#a0aec0-fg}${state.session.id}{/}`,
763
+ `{#718096-fg}│{/}`,
764
+ `{#c084fc-fg}${state.session.provider}{/}`,
765
+ `{#718096-fg}│{/}`,
766
+ `{#60a5fa-fg}${modelShort}{/}`,
767
+ `{#718096-fg}│{/}`,
768
+ `{#a0aec0-fg}${msgs} messages{/}`,
769
+ `{#718096-fg}│{/}`,
770
+ `{#34d399-fg}${cost}{/}`,
771
+ ].join(' ');
772
+ ui.statusBar.setContent(' ' + status);
773
+ }
774
+ // Command Handler
775
+ async function handleCommand(cmd, state, ui) {
776
+ const [command, ...args] = cmd.slice(1).split(' ');
777
+ switch (command) {
778
+ case 'clear':
779
+ case 'c':
780
+ state.session.messages = [];
781
+ state.session.claudeSessionId = undefined;
782
+ state.session.totalCost = 0;
783
+ state.session.totalTokens = 0;
784
+ ui.chatLog.setContent('');
785
+ ui.chatLog.log('');
786
+ ui.chatLog.log('{#34d399-fg}✓ Conversation cleared{/}');
787
+ ui.chatLog.log('');
788
+ updateStatusBar(state, ui);
789
+ safeRender();
790
+ break;
791
+ case 'provider':
792
+ case 'p': {
793
+ const next = args[0];
794
+ ui.chatLog.log('');
795
+ if (!next) {
796
+ ui.chatLog.log(` {bold}Current provider:{/bold} {#c084fc-fg}${state.session.provider}{/}`);
797
+ ui.chatLog.log(' {#718096-fg}Available providers:{/}');
798
+ ui.chatLog.log(' {#a0aec0-fg}claude{/}');
799
+ ui.chatLog.log(' {#a0aec0-fg}codex{/}');
800
+ }
801
+ else if (next !== 'claude' && next !== 'codex') {
802
+ ui.chatLog.log(` {#ef4444-fg}Unknown provider: ${next}{/}`);
803
+ }
804
+ else {
805
+ state.session.provider = next;
806
+ state.session.model = getDefaultChatModel(next);
807
+ state.session.claudeSessionId = undefined;
808
+ ui.chatLog.log(` {#34d399-fg}✓ Provider changed to {bold}${next}{/bold}{/}`);
809
+ ui.chatLog.log(` {#34d399-fg}✓ Model changed to {bold}${state.session.model}{/bold}{/}`);
810
+ updateStatusBar(state, ui);
811
+ }
812
+ ui.chatLog.log('');
813
+ safeRender();
814
+ break;
815
+ }
816
+ case 'model':
817
+ case 'm': {
818
+ const newModel = args[0];
819
+ ui.chatLog.log('');
820
+ if (!newModel) {
821
+ ui.chatLog.log(` {bold}Current provider:{/bold} {#c084fc-fg}${state.session.provider}{/}`);
822
+ ui.chatLog.log(` {bold}Current model:{/bold} {#60a5fa-fg}${shortenChatModel(state.session.model)}{/}`);
823
+ ui.chatLog.log('');
824
+ ui.chatLog.log(' {#718096-fg}Available models:{/}');
825
+ if (state.session.provider === 'claude') {
826
+ ui.chatLog.log(' {#a0aec0-fg}sonnet{/} {#718096-fg}→{/} claude-sonnet-4-5');
827
+ ui.chatLog.log(' {#a0aec0-fg}haiku{/} {#718096-fg}→{/} claude-haiku-4-5');
828
+ ui.chatLog.log(' {#a0aec0-fg}opus{/} {#718096-fg}→{/} claude-opus-4-6');
829
+ }
830
+ else if (state.session.provider === 'responses') {
831
+ ui.chatLog.log(' {#a0aec0-fg}auto{/} {#718096-fg}→{/} auto');
832
+ ui.chatLog.log(' {#a0aec0-fg}gpt-5{/} {#718096-fg}→{/} gpt-5');
833
+ ui.chatLog.log(' {#a0aec0-fg}gpt-4o{/} {#718096-fg}→{/} gpt-4o');
834
+ }
835
+ else {
836
+ ui.chatLog.log(' {#a0aec0-fg}codex{/} {#718096-fg}→{/} gpt-5-codex');
837
+ }
838
+ }
839
+ else {
840
+ state.session.model = resolveChatModel(newModel, state.session.provider);
841
+ state.session.claudeSessionId = undefined;
842
+ const shortName = shortenChatModel(state.session.model);
843
+ ui.chatLog.log(` {#34d399-fg}✓ Model changed to {bold}${shortName}{/bold}{/}`);
844
+ updateStatusBar(state, ui);
845
+ }
846
+ ui.chatLog.log('');
847
+ safeRender();
848
+ break;
849
+ }
850
+ case 'save': {
851
+ const name = args[0] || state.session.id;
852
+ state.session.id = name;
853
+ await saveSession(state.session);
854
+ ui.chatLog.log('');
855
+ ui.chatLog.log(` {#34d399-fg}✓ Session saved: {bold}${name}{/bold}{/}`);
856
+ ui.chatLog.log('');
857
+ updateStatusBar(state, ui);
858
+ safeRender();
859
+ break;
860
+ }
861
+ case 'help':
862
+ case 'h':
863
+ case '?':
864
+ ui.chatLog.log('');
865
+ ui.chatLog.log(' {bold}Available Commands{/bold}');
866
+ ui.chatLog.log('');
867
+ ui.chatLog.log(' {#60a5fa-fg}/clear{/} Clear conversation');
868
+ ui.chatLog.log(' {#60a5fa-fg}/provider{/} [id] Change provider {#718096-fg}(claude/codex){/}');
869
+ ui.chatLog.log(' {#60a5fa-fg}/model{/} [name] Change model {#718096-fg}(sonnet/haiku/opus){/}');
870
+ ui.chatLog.log(' {#60a5fa-fg}/save{/} [name] Save session');
871
+ ui.chatLog.log(' {#60a5fa-fg}/help{/} Show this help');
872
+ ui.chatLog.log('');
873
+ ui.chatLog.log(' {bold}Navigation{/bold}');
874
+ ui.chatLog.log('');
875
+ ui.chatLog.log(' {#718096-fg}1-4{/} Switch tabs directly');
876
+ ui.chatLog.log(' {#718096-fg}Tab/Shift+Tab{/} Cycle through tabs');
877
+ ui.chatLog.log(' {#718096-fg}Esc{/} Exit input mode (blur)');
878
+ ui.chatLog.log(' {#718096-fg}i / Enter{/} Focus input (from chat)');
879
+ ui.chatLog.log(' {#718096-fg}Ctrl+C{/} Exit (double press to confirm)');
880
+ ui.chatLog.log('');
881
+ safeRender();
882
+ break;
883
+ default:
884
+ ui.chatLog.log('');
885
+ ui.chatLog.log(` {#ef4444-fg}Unknown command: /{bold}${command}{/bold}{/}`);
886
+ ui.chatLog.log(` {#718096-fg}Type {/}{#60a5fa-fg}/help{/}{#718096-fg} for available commands{/}`);
887
+ ui.chatLog.log('');
888
+ safeRender();
889
+ }
890
+ return false;
891
+ }
892
+ // Main
893
+ export async function main() {
894
+ const defaultProvider = loadDefaultProvider();
895
+ const loadArg = process.argv[2];
896
+ let session;
897
+ if (loadArg && loadArg !== '--' && !loadArg.startsWith('-')) {
898
+ const loaded = await loadSession(loadArg);
899
+ if (loaded) {
900
+ session = loaded;
901
+ }
902
+ else {
903
+ session = {
904
+ id: loadArg,
905
+ provider: defaultProvider,
906
+ model: getDefaultChatModel(defaultProvider),
907
+ messages: [],
908
+ totalCost: 0,
909
+ totalTokens: 0,
910
+ createdAt: new Date().toISOString(),
911
+ updatedAt: new Date().toISOString(),
912
+ };
913
+ }
914
+ }
915
+ else {
916
+ session = {
917
+ id: generateSessionId(),
918
+ provider: defaultProvider,
919
+ model: getDefaultChatModel(defaultProvider),
920
+ messages: [],
921
+ totalCost: 0,
922
+ totalTokens: 0,
923
+ createdAt: new Date().toISOString(),
924
+ updatedAt: new Date().toISOString(),
925
+ };
926
+ }
927
+ const state = {
928
+ session,
929
+ currentTab: 0,
930
+ inputMode: 'normal',
931
+ multilineBuffer: [],
932
+ showBinary: false,
933
+ diagnostics: {
934
+ lastResponseTime: 0,
935
+ avgTokensPerSec: 0,
936
+ totalRequests: 0,
937
+ },
938
+ };
939
+ const ui = createUI();
940
+ screenRef = ui.screen; // safeRender용 참조 설정
941
+ updateStatusBar(state, ui);
942
+ updateTabBar(ui, state.currentTab);
943
+ // Restore chat history - Claude Code style with proper line breaks
944
+ for (const msg of session.messages) {
945
+ ui.chatLog.log('');
946
+ if (msg.role === 'user') {
947
+ ui.chatLog.log(`{#60a5fa-fg}{bold}▸ You{/bold}{/}`);
948
+ // Split multiline user messages
949
+ const userLines = msg.content.split('\n');
950
+ for (const line of userLines) {
951
+ ui.chatLog.log(line ? ` ${line}` : ' ');
952
+ }
953
+ }
954
+ else {
955
+ ui.chatLog.log(`{#34d399-fg}{bold}▸ Assistant{/bold}{/}`);
956
+ // Split multiline assistant messages properly
957
+ const assistantLines = msg.content.split('\n');
958
+ for (const line of assistantLines) {
959
+ ui.chatLog.log(line ? ` ${line}` : ' ');
960
+ }
961
+ if (msg.cost) {
962
+ ui.chatLog.log(` {#718096-fg}$${msg.cost.toFixed(4)}{/}`);
963
+ }
964
+ }
965
+ }
966
+ if (session.messages.length > 0) {
967
+ ui.chatLog.log('');
968
+ }
969
+ // Key bindings
970
+ ui.screen.key(['1'], () => switchTab(state, ui, 0));
971
+ ui.screen.key(['2'], () => switchTab(state, ui, 1));
972
+ ui.screen.key(['3'], () => switchTab(state, ui, 2));
973
+ ui.screen.key(['4'], () => switchTab(state, ui, 3));
974
+ ui.screen.key(['5'], () => switchTab(state, ui, 4));
975
+ ui.screen.key(['tab'], () => {
976
+ const next = (state.currentTab + 1) % 6;
977
+ switchTab(state, ui, next);
978
+ });
979
+ ui.screen.key(['S-tab'], () => {
980
+ const prev = (state.currentTab - 1 + 6) % 6;
981
+ switchTab(state, ui, prev);
982
+ });
983
+ // Ctrl+C: Clear input or exit (Claude Code style)
984
+ let ctrlCPressed = false;
985
+ ui.screen.key(['C-c'], async () => {
986
+ const currentValue = ui.inputBox.getValue();
987
+ if (currentValue && currentValue.trim()) {
988
+ // If input has text, just clear it
989
+ ui.inputBox.clearValue();
990
+ ui.inputBox.focus();
991
+ safeRender();
992
+ ctrlCPressed = false;
993
+ }
994
+ else {
995
+ // If input is empty, exit with double Ctrl+C
996
+ if (ctrlCPressed) {
997
+ await saveSession(state.session);
998
+ process.exit(0);
999
+ }
1000
+ else {
1001
+ ctrlCPressed = true;
1002
+ ui.statusBar.setContent(' {#f59e0b-fg}Press Ctrl+C again to exit{/}');
1003
+ safeRender();
1004
+ setTimeout(() => {
1005
+ ctrlCPressed = false;
1006
+ updateStatusBar(state, ui);
1007
+ safeRender();
1008
+ }, 2000);
1009
+ }
1010
+ }
1011
+ });
1012
+ // Escape: Clear input and blur (exit input mode)
1013
+ ui.screen.key(['escape'], () => {
1014
+ const currentValue = ui.inputBox.getValue();
1015
+ if (currentValue && currentValue.trim()) {
1016
+ // Clear input if has content
1017
+ ui.inputBox.clearValue();
1018
+ }
1019
+ // Blur input box to exit input mode
1020
+ ui.chatLog.focus();
1021
+ safeRender();
1022
+ });
1023
+ // Enter in chatLog: focus input
1024
+ ui.chatLog.key(['enter', 'i'], () => {
1025
+ ui.inputBox.focus();
1026
+ safeRender();
1027
+ });
1028
+ // Shift+Enter: Insert newline (handled by textarea by default)
1029
+ // Enter: Submit message
1030
+ ui.inputBox.key(['enter'], async () => {
1031
+ const value = ui.inputBox.getValue();
1032
+ const trimmed = value.trim();
1033
+ if (!trimmed)
1034
+ return;
1035
+ ui.inputBox.clearValue();
1036
+ ui.inputBox.focus();
1037
+ safeRender();
1038
+ if (trimmed.startsWith('/')) {
1039
+ await handleCommand(trimmed, state, ui);
1040
+ }
1041
+ else {
1042
+ await sendMessage(state, ui, trimmed);
1043
+ }
1044
+ });
1045
+ // Focus input by default
1046
+ ui.inputBox.focus();
1047
+ // Handle terminal resize (important for tmux) — debounce로 연속 resize 시 깜빡임 방지
1048
+ let resizeTimer = null;
1049
+ process.stdout.on('resize', () => {
1050
+ if (resizeTimer)
1051
+ clearTimeout(resizeTimer);
1052
+ resizeTimer = setTimeout(() => {
1053
+ ui.screen.alloc();
1054
+ ui.screen.realloc();
1055
+ safeRender();
1056
+ }, 50);
1057
+ });
1058
+ // Render
1059
+ safeRender();
1060
+ // Auto-refresh Projects/WorkItems/Stuck tabs every 5s
1061
+ setInterval(() => {
1062
+ if (state.currentTab === 1)
1063
+ loadProjectsData(ui.projectsBox);
1064
+ if (state.currentTab === 2)
1065
+ loadWorkItemsData(ui.workItemsBox);
1066
+ if (state.currentTab === 3)
1067
+ loadStuckData(ui.stuckBox);
1068
+ if (state.currentTab === 4)
1069
+ loadWorkItemsData(ui.workItemsBox);
1070
+ safeRender();
1071
+ }, 5000);
1072
+ // System logs (example - hook into eventHub in real implementation)
1073
+ ui.logsBox.log('{gray-fg}System initialized{/gray-fg}');
1074
+ }
1075
+ // Auto-run if called directly
1076
+ if (import.meta.url === `file://${process.argv[1]}`) {
1077
+ main().catch((err) => {
1078
+ console.error('Fatal:', err);
1079
+ process.exit(1);
1080
+ });
1081
+ }
1082
+ //# sourceMappingURL=chatTui.js.map