@quickchatai/quickreview 0.0.0-stage → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1443) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +385 -2
  3. package/THIRD-PARTY-NOTICES.md +134 -0
  4. package/agents/pass-abstraction.md +64 -0
  5. package/agents/pass-ask-human.md +134 -0
  6. package/agents/pass-backcompat.md +67 -0
  7. package/agents/pass-baseline.md +61 -0
  8. package/agents/pass-behaviour-delta.md +64 -0
  9. package/agents/pass-bounds.md +36 -0
  10. package/agents/pass-claims.md +31 -0
  11. package/agents/pass-concurrency.md +168 -0
  12. package/agents/pass-consistency.md +57 -0
  13. package/agents/pass-contracts.md +30 -0
  14. package/agents/pass-data-safety.md +54 -0
  15. package/agents/pass-deferred.md +35 -0
  16. package/agents/pass-delivery.md +37 -0
  17. package/agents/pass-duplication.md +60 -0
  18. package/agents/pass-intent.md +63 -0
  19. package/agents/pass-lint-conformance.md +46 -0
  20. package/agents/pass-maintainability.md +67 -0
  21. package/agents/pass-placement.md +68 -0
  22. package/agents/pass-prod-risk.md +24 -0
  23. package/agents/pass-rollout.md +32 -0
  24. package/agents/pass-roundtrip.md +46 -0
  25. package/agents/pass-security.md +31 -0
  26. package/agents/pass-simplicity.md +68 -0
  27. package/agents/pass-statelessness.md +27 -0
  28. package/agents/pass-style.md +37 -0
  29. package/agents/pass-sweep.md +57 -0
  30. package/agents/pass-tests.md +58 -0
  31. package/agents/pass-ui.md +23 -0
  32. package/agents/pass-validate.md +50 -0
  33. package/agents/pass-widened.md +46 -0
  34. package/agents/scan/pass-scan.md +86 -0
  35. package/bin/qcr.js +11 -0
  36. package/config.example.toml +1067 -0
  37. package/deploy/ansible/README.md +356 -0
  38. package/deploy/ansible/group_vars/all.yml +212 -0
  39. package/deploy/ansible/inventory.example.ini +25 -0
  40. package/deploy/ansible/playbook.yml +360 -0
  41. package/deploy/collect-secrets.sh +289 -0
  42. package/deploy/collect-slack-secrets.mjs +1190 -0
  43. package/deploy/github-app-manifest.json +31 -0
  44. package/deploy/manifest.schema.json +75 -0
  45. package/deploy/qcr-update.sh +803 -0
  46. package/deploy/reviewer/AGENTS.override.md +12 -0
  47. package/dist/extensions/cli/bash-guard-ambient.js +42 -0
  48. package/dist/extensions/cli/bash-guard-ambient.js.map +1 -0
  49. package/dist/extensions/cli/bash-guard.js +5 -0
  50. package/dist/extensions/cli/bash-guard.js.map +1 -0
  51. package/dist/extensions/cli/companion-guard.js +5 -0
  52. package/dist/extensions/cli/companion-guard.js.map +1 -0
  53. package/dist/extensions/cli/debug-round.js +8 -0
  54. package/dist/extensions/cli/debug-round.js.map +1 -0
  55. package/dist/extensions/cli/inject-bridge.js +5 -0
  56. package/dist/extensions/cli/inject-bridge.js.map +1 -0
  57. package/dist/extensions/cli/ledger-pin.js +5 -0
  58. package/dist/extensions/cli/ledger-pin.js.map +1 -0
  59. package/dist/extensions/cli/lens.js +13 -0
  60. package/dist/extensions/cli/lens.js.map +1 -0
  61. package/dist/extensions/cli/muted-theme.js +5 -0
  62. package/dist/extensions/cli/muted-theme.js.map +1 -0
  63. package/dist/extensions/cli/onboarding.js +5 -0
  64. package/dist/extensions/cli/onboarding.js.map +1 -0
  65. package/dist/extensions/cli/setup.js +5 -0
  66. package/dist/extensions/cli/setup.js.map +1 -0
  67. package/dist/extensions/cli/tui-view.js +5 -0
  68. package/dist/extensions/cli/tui-view.js.map +1 -0
  69. package/dist/extensions/companion-guard.js +361 -0
  70. package/dist/extensions/companion-guard.js.map +1 -0
  71. package/dist/extensions/debug-round.js +204 -0
  72. package/dist/extensions/debug-round.js.map +1 -0
  73. package/dist/extensions/inject-bridge.js +603 -0
  74. package/dist/extensions/inject-bridge.js.map +1 -0
  75. package/dist/extensions/muted-theme.js +12 -0
  76. package/dist/extensions/muted-theme.js.map +1 -0
  77. package/dist/extensions/onboarding.js +175 -0
  78. package/dist/extensions/onboarding.js.map +1 -0
  79. package/dist/extensions/setup-replay.js +269 -0
  80. package/dist/extensions/setup-replay.js.map +1 -0
  81. package/dist/extensions/setup-scan.js +998 -0
  82. package/dist/extensions/setup-scan.js.map +1 -0
  83. package/dist/extensions/setup-triage.js +175 -0
  84. package/dist/extensions/setup-triage.js.map +1 -0
  85. package/dist/extensions/setup.js +1160 -0
  86. package/dist/extensions/setup.js.map +1 -0
  87. package/dist/extensions/tui-view.js +389 -0
  88. package/dist/extensions/tui-view.js.map +1 -0
  89. package/dist/extensions/vendor/openviking-pi/client.js +376 -0
  90. package/dist/extensions/vendor/openviking-pi/client.js.map +1 -0
  91. package/dist/extensions/vendor/openviking-pi/config.js +189 -0
  92. package/dist/extensions/vendor/openviking-pi/config.js.map +1 -0
  93. package/dist/extensions/vendor/openviking-pi/index.js +421 -0
  94. package/dist/extensions/vendor/openviking-pi/index.js.map +1 -0
  95. package/dist/extensions/vendor/openviking-pi/lib/capture-adapter.mjs +86 -0
  96. package/dist/extensions/vendor/openviking-pi/lib/capture-adapter.mjs.map +1 -0
  97. package/dist/extensions/vendor/openviking-pi/lib/takeover-core.mjs +408 -0
  98. package/dist/extensions/vendor/openviking-pi/lib/takeover-core.mjs.map +1 -0
  99. package/dist/extensions/vendor/openviking-pi/lib/uri-guard-adapter.mjs +41 -0
  100. package/dist/extensions/vendor/openviking-pi/lib/uri-guard-adapter.mjs.map +1 -0
  101. package/dist/extensions/vendor/openviking-pi/qcr-hint.js +290 -0
  102. package/dist/extensions/vendor/openviking-pi/qcr-hint.js.map +1 -0
  103. package/dist/extensions/vendor/openviking-pi/qcr-honest.js +148 -0
  104. package/dist/extensions/vendor/openviking-pi/qcr-honest.js.map +1 -0
  105. package/dist/extensions/vendor/openviking-pi/qcr-hooks.js +68 -0
  106. package/dist/extensions/vendor/openviking-pi/qcr-hooks.js.map +1 -0
  107. package/dist/extensions/vendor/openviking-pi/qcr-leaf.js +77 -0
  108. package/dist/extensions/vendor/openviking-pi/qcr-leaf.js.map +1 -0
  109. package/dist/extensions/vendor/openviking-pi/qcr-lesson.js +216 -0
  110. package/dist/extensions/vendor/openviking-pi/qcr-lesson.js.map +1 -0
  111. package/dist/extensions/vendor/openviking-pi/qcr-namespaces.js +154 -0
  112. package/dist/extensions/vendor/openviking-pi/qcr-namespaces.js.map +1 -0
  113. package/dist/extensions/vendor/openviking-pi/qcr-recall.js +254 -0
  114. package/dist/extensions/vendor/openviking-pi/qcr-recall.js.map +1 -0
  115. package/dist/extensions/vendor/openviking-pi/qcr-shim.js +94 -0
  116. package/dist/extensions/vendor/openviking-pi/qcr-shim.js.map +1 -0
  117. package/dist/extensions/vendor/openviking-pi/qcr-write.js +333 -0
  118. package/dist/extensions/vendor/openviking-pi/qcr-write.js.map +1 -0
  119. package/dist/extensions/vendor/openviking-pi/recall.js +108 -0
  120. package/dist/extensions/vendor/openviking-pi/recall.js.map +1 -0
  121. package/dist/extensions/vendor/openviking-pi/shared/capture-utils.mjs +529 -0
  122. package/dist/extensions/vendor/openviking-pi/shared/capture-utils.mjs.map +1 -0
  123. package/dist/extensions/vendor/openviking-pi/shared/credentials.mjs +205 -0
  124. package/dist/extensions/vendor/openviking-pi/shared/credentials.mjs.map +1 -0
  125. package/dist/extensions/vendor/openviking-pi/shared/pending-queue.mjs +442 -0
  126. package/dist/extensions/vendor/openviking-pi/shared/pending-queue.mjs.map +1 -0
  127. package/dist/extensions/vendor/openviking-pi/shared/profile-inject.mjs +286 -0
  128. package/dist/extensions/vendor/openviking-pi/shared/profile-inject.mjs.map +1 -0
  129. package/dist/extensions/vendor/openviking-pi/shared/recall-compress-core.mjs +189 -0
  130. package/dist/extensions/vendor/openviking-pi/shared/recall-compress-core.mjs.map +1 -0
  131. package/dist/extensions/vendor/openviking-pi/shared/recall-core.mjs +580 -0
  132. package/dist/extensions/vendor/openviking-pi/shared/recall-core.mjs.map +1 -0
  133. package/dist/extensions/vendor/openviking-pi/shared/retryable.mjs +11 -0
  134. package/dist/extensions/vendor/openviking-pi/shared/retryable.mjs.map +1 -0
  135. package/dist/extensions/vendor/openviking-pi/shared/session-model.mjs +63 -0
  136. package/dist/extensions/vendor/openviking-pi/shared/session-model.mjs.map +1 -0
  137. package/dist/extensions/vendor/openviking-pi/shared/uri-guard.mjs +58 -0
  138. package/dist/extensions/vendor/openviking-pi/shared/uri-guard.mjs.map +1 -0
  139. package/dist/extensions/vendor/openviking-pi/shared/workspace-peer.mjs +16 -0
  140. package/dist/extensions/vendor/openviking-pi/shared/workspace-peer.mjs.map +1 -0
  141. package/dist/extensions/vendor/openviking-pi/sync.js +127 -0
  142. package/dist/extensions/vendor/openviking-pi/sync.js.map +1 -0
  143. package/dist/extensions/vendor/openviking-pi/takeover.js +25 -0
  144. package/dist/extensions/vendor/openviking-pi/takeover.js.map +1 -0
  145. package/dist/extensions/vendor/openviking-pi/tools.js +417 -0
  146. package/dist/extensions/vendor/openviking-pi/tools.js.map +1 -0
  147. package/dist/src/anomalies.js +483 -0
  148. package/dist/src/anomalies.js.map +1 -0
  149. package/dist/src/answerworker.js +180 -0
  150. package/dist/src/answerworker.js.map +1 -0
  151. package/dist/src/appstamp.js +68 -0
  152. package/dist/src/appstamp.js.map +1 -0
  153. package/dist/src/archive/admission.js +3 -0
  154. package/dist/src/archive/admission.js.map +1 -0
  155. package/dist/src/archive/archivedb.js +474 -0
  156. package/dist/src/archive/archivedb.js.map +1 -0
  157. package/dist/src/archive/archiver.js +1770 -0
  158. package/dist/src/archive/archiver.js.map +1 -0
  159. package/dist/src/archive/archivewrite.js +198 -0
  160. package/dist/src/archive/archivewrite.js.map +1 -0
  161. package/dist/src/archive/bundle.js +266 -0
  162. package/dist/src/archive/bundle.js.map +1 -0
  163. package/dist/src/archive/dbmove.js +638 -0
  164. package/dist/src/archive/dbmove.js.map +1 -0
  165. package/dist/src/archive/duplicatecounts.js +80 -0
  166. package/dist/src/archive/duplicatecounts.js.map +1 -0
  167. package/dist/src/archive/eligibility.js +113 -0
  168. package/dist/src/archive/eligibility.js.map +1 -0
  169. package/dist/src/archive/extract.js +288 -0
  170. package/dist/src/archive/extract.js.map +1 -0
  171. package/dist/src/archive/fsutil.js +330 -0
  172. package/dist/src/archive/fsutil.js.map +1 -0
  173. package/dist/src/archive/gzfile.js +277 -0
  174. package/dist/src/archive/gzfile.js.map +1 -0
  175. package/dist/src/archive/kinds.js +22 -0
  176. package/dist/src/archive/kinds.js.map +1 -0
  177. package/dist/src/archive/livecheckpoint.js +178 -0
  178. package/dist/src/archive/livecheckpoint.js.map +1 -0
  179. package/dist/src/archive/liveretention.js +145 -0
  180. package/dist/src/archive/liveretention.js.map +1 -0
  181. package/dist/src/archive/manifest.js +284 -0
  182. package/dist/src/archive/manifest.js.map +1 -0
  183. package/dist/src/archive/overseer.js +283 -0
  184. package/dist/src/archive/overseer.js.map +1 -0
  185. package/dist/src/archive/piglobal.js +129 -0
  186. package/dist/src/archive/piglobal.js.map +1 -0
  187. package/dist/src/archive/plan.js +398 -0
  188. package/dist/src/archive/plan.js.map +1 -0
  189. package/dist/src/archive/prarchive.js +831 -0
  190. package/dist/src/archive/prarchive.js.map +1 -0
  191. package/dist/src/archive/prfiles.js +303 -0
  192. package/dist/src/archive/prfiles.js.map +1 -0
  193. package/dist/src/archive/report.js +169 -0
  194. package/dist/src/archive/report.js.map +1 -0
  195. package/dist/src/archive/restore.js +276 -0
  196. package/dist/src/archive/restore.js.map +1 -0
  197. package/dist/src/archive/rows.js +106 -0
  198. package/dist/src/archive/rows.js.map +1 -0
  199. package/dist/src/archive/seal.js +480 -0
  200. package/dist/src/archive/seal.js.map +1 -0
  201. package/dist/src/archive/status.js +528 -0
  202. package/dist/src/archive/status.js.map +1 -0
  203. package/dist/src/archive/storepass.js +409 -0
  204. package/dist/src/archive/storepass.js.map +1 -0
  205. package/dist/src/backfill.js +217 -0
  206. package/dist/src/backfill.js.map +1 -0
  207. package/dist/src/bench/cost.js +87 -0
  208. package/dist/src/bench/exec.js +76 -0
  209. package/dist/src/bench/values.js +14 -0
  210. package/dist/src/botcontrol.js +127 -0
  211. package/dist/src/botcontrol.js.map +1 -0
  212. package/dist/src/botworker.js +805 -0
  213. package/dist/src/botworker.js.map +1 -0
  214. package/dist/src/capture.js +234 -0
  215. package/dist/src/capture.js.map +1 -0
  216. package/dist/src/cases.js +1491 -0
  217. package/dist/src/cases.js.map +1 -0
  218. package/dist/src/channelfs.js +27 -0
  219. package/dist/src/channelfs.js.map +1 -0
  220. package/dist/src/checklist.js +312 -0
  221. package/dist/src/checklist.js.map +1 -0
  222. package/dist/src/ciretry.js +91 -0
  223. package/dist/src/ciretry.js.map +1 -0
  224. package/dist/src/cli.js +1916 -0
  225. package/dist/src/cli.js.map +1 -0
  226. package/dist/src/cliops.js +333 -0
  227. package/dist/src/cliops.js.map +1 -0
  228. package/dist/src/clonedir.js +15 -0
  229. package/dist/src/clonedir.js.map +1 -0
  230. package/dist/src/commandeffects.js +43 -0
  231. package/dist/src/commandeffects.js.map +1 -0
  232. package/dist/src/commands.js +1312 -0
  233. package/dist/src/commands.js.map +1 -0
  234. package/dist/src/companioninbox.js +203 -0
  235. package/dist/src/companioninbox.js.map +1 -0
  236. package/dist/src/compare.js +673 -0
  237. package/dist/src/compare.js.map +1 -0
  238. package/dist/src/config.js +1027 -0
  239. package/dist/src/config.js.map +1 -0
  240. package/dist/src/configcheck.js +111 -0
  241. package/dist/src/configcheck.js.map +1 -0
  242. package/dist/src/coreext.js +43 -0
  243. package/dist/src/coreext.js.map +1 -0
  244. package/dist/src/daemon.js +929 -0
  245. package/dist/src/daemon.js.map +1 -0
  246. package/dist/src/debuground.js +731 -0
  247. package/dist/src/debuground.js.map +1 -0
  248. package/dist/src/debugroundpi.js +219 -0
  249. package/dist/src/debugroundpi.js.map +1 -0
  250. package/dist/src/diagnostics.js +14 -0
  251. package/dist/src/diagnostics.js.map +1 -0
  252. package/dist/src/digest.js +139 -0
  253. package/dist/src/digest.js.map +1 -0
  254. package/dist/src/dispatch.js +1726 -0
  255. package/dist/src/dispatch.js.map +1 -0
  256. package/dist/src/engine/answerguard.js +18 -0
  257. package/dist/src/engine/answerguard.js.map +1 -0
  258. package/dist/src/engine/botsdk.js +262 -0
  259. package/dist/src/engine/botsdk.js.map +1 -0
  260. package/dist/src/engine/caserunner-sdk.js +332 -0
  261. package/dist/src/engine/caserunner-sdk.js.map +1 -0
  262. package/dist/src/engine/debugpi.js +194 -0
  263. package/dist/src/engine/debugpi.js.map +1 -0
  264. package/dist/src/eod.js +473 -0
  265. package/dist/src/eod.js.map +1 -0
  266. package/dist/src/eodpinwatch.js +391 -0
  267. package/dist/src/eodpinwatch.js.map +1 -0
  268. package/dist/src/escalation.js +1009 -0
  269. package/dist/src/escalation.js.map +1 -0
  270. package/dist/src/eventloop.js +779 -0
  271. package/dist/src/eventloop.js.map +1 -0
  272. package/dist/src/execboundary.js +430 -0
  273. package/dist/src/execboundary.js.map +1 -0
  274. package/dist/src/feedback.js +915 -0
  275. package/dist/src/feedback.js.map +1 -0
  276. package/dist/src/findingscheck.js +200 -0
  277. package/dist/src/findingscheck.js.map +1 -0
  278. package/dist/src/fsdenied.js +26 -0
  279. package/dist/src/fsdenied.js.map +1 -0
  280. package/dist/src/ghread.js +181 -0
  281. package/dist/src/ghread.js.map +1 -0
  282. package/dist/src/github.js +1063 -0
  283. package/dist/src/github.js.map +1 -0
  284. package/dist/src/homes.js +103 -0
  285. package/dist/src/homes.js.map +1 -0
  286. package/dist/src/hostroute.js +24 -0
  287. package/dist/src/hostroute.js.map +1 -0
  288. package/dist/src/improvements.js +625 -0
  289. package/dist/src/improvements.js.map +1 -0
  290. package/dist/src/install.js +946 -0
  291. package/dist/src/install.js.map +1 -0
  292. package/dist/src/installkind.js +40 -0
  293. package/dist/src/installkind.js.map +1 -0
  294. package/dist/src/ipc/capability.js +286 -0
  295. package/dist/src/ipc/capability.js.map +1 -0
  296. package/dist/src/ipc/client.js +226 -0
  297. package/dist/src/ipc/client.js.map +1 -0
  298. package/dist/src/ipc/control.js +70 -0
  299. package/dist/src/ipc/control.js.map +1 -0
  300. package/dist/src/ipc/ghreadshim.js +77 -0
  301. package/dist/src/ipc/ghreadshim.js.map +1 -0
  302. package/dist/src/ipc/launcher.js +65 -0
  303. package/dist/src/ipc/launcher.js.map +1 -0
  304. package/dist/src/ipc/permits.js +293 -0
  305. package/dist/src/ipc/permits.js.map +1 -0
  306. package/dist/src/ipc/postshim.js +137 -0
  307. package/dist/src/ipc/postshim.js.map +1 -0
  308. package/dist/src/ipc/protocol.js +239 -0
  309. package/dist/src/ipc/protocol.js.map +1 -0
  310. package/dist/src/ipc/server.js +312 -0
  311. package/dist/src/ipc/server.js.map +1 -0
  312. package/dist/src/ipc/workerspec.js +148 -0
  313. package/dist/src/ipc/workerspec.js.map +1 -0
  314. package/dist/src/learner/learner.js +1272 -0
  315. package/dist/src/learner/learner.js.map +1 -0
  316. package/dist/src/learner/miner.js +948 -0
  317. package/dist/src/learner/miner.js.map +1 -0
  318. package/dist/src/learner/packet.js +216 -0
  319. package/dist/src/learner/packet.js.map +1 -0
  320. package/dist/src/learner/receipt.js +135 -0
  321. package/dist/src/learner/receipt.js.map +1 -0
  322. package/dist/src/learner/status.js +38 -0
  323. package/dist/src/learner/status.js.map +1 -0
  324. package/dist/src/ledgercheck.js +120 -0
  325. package/dist/src/ledgercheck.js.map +1 -0
  326. package/dist/src/lessonledger.js +451 -0
  327. package/dist/src/lessonledger.js.map +1 -0
  328. package/dist/src/lessonselect.js +639 -0
  329. package/dist/src/lessonselect.js.map +1 -0
  330. package/dist/src/lessonshadow.js +540 -0
  331. package/dist/src/lessonshadow.js.map +1 -0
  332. package/dist/src/levers.js +302 -0
  333. package/dist/src/levers.js.map +1 -0
  334. package/dist/src/live/projection.js +450 -0
  335. package/dist/src/live/projection.js.map +1 -0
  336. package/dist/src/live/publish.js +83 -0
  337. package/dist/src/live/publish.js.map +1 -0
  338. package/dist/src/live/read.js +60 -0
  339. package/dist/src/live/read.js.map +1 -0
  340. package/dist/src/livecli.js +288 -0
  341. package/dist/src/livecli.js.map +1 -0
  342. package/dist/src/loginhint.js +42 -0
  343. package/dist/src/loginhint.js.map +1 -0
  344. package/dist/src/loginrefresh/atomic.js +66 -0
  345. package/dist/src/loginrefresh/atomic.js.map +1 -0
  346. package/dist/src/loginrefresh/lock.js +93 -0
  347. package/dist/src/loginrefresh/lock.js.map +1 -0
  348. package/dist/src/loginrefresh/main.js +58 -0
  349. package/dist/src/loginrefresh/main.js.map +1 -0
  350. package/dist/src/loginrefresh/pirefresh.js +49 -0
  351. package/dist/src/loginrefresh/pirefresh.js.map +1 -0
  352. package/dist/src/loginrefresh/refresher.js +286 -0
  353. package/dist/src/loginrefresh/refresher.js.map +1 -0
  354. package/dist/src/loginrefresh/supervisor.js +253 -0
  355. package/dist/src/loginrefresh/supervisor.js.map +1 -0
  356. package/dist/src/loginrefresh/types.js +4 -0
  357. package/dist/src/loginrefresh/types.js.map +1 -0
  358. package/dist/src/memory/context.js +251 -0
  359. package/dist/src/memory/context.js.map +1 -0
  360. package/dist/src/memory/datafence.js +5 -0
  361. package/dist/src/memory/datafence.js.map +1 -0
  362. package/dist/src/memory/delivery.js +131 -0
  363. package/dist/src/memory/delivery.js.map +1 -0
  364. package/dist/src/memory/eventtags.js +81 -0
  365. package/dist/src/memory/eventtags.js.map +1 -0
  366. package/dist/src/memory/health.js +713 -0
  367. package/dist/src/memory/health.js.map +1 -0
  368. package/dist/src/memory/import.js +504 -0
  369. package/dist/src/memory/import.js.map +1 -0
  370. package/dist/src/memory/layout.js +252 -0
  371. package/dist/src/memory/layout.js.map +1 -0
  372. package/dist/src/memory/legacy-file.js +100 -0
  373. package/dist/src/memory/legacy-file.js.map +1 -0
  374. package/dist/src/memory/lessons.js +370 -0
  375. package/dist/src/memory/lessons.js.map +1 -0
  376. package/dist/src/memory/ovsession.js +449 -0
  377. package/dist/src/memory/ovsession.js.map +1 -0
  378. package/dist/src/memory/relayout.js +259 -0
  379. package/dist/src/memory/relayout.js.map +1 -0
  380. package/dist/src/memory/roundactivity.js +180 -0
  381. package/dist/src/memory/roundactivity.js.map +1 -0
  382. package/dist/src/memory/selection.js +690 -0
  383. package/dist/src/memory/selection.js.map +1 -0
  384. package/dist/src/memory/shadowstatus.js +69 -0
  385. package/dist/src/memory/shadowstatus.js.map +1 -0
  386. package/dist/src/memory/store.js +83 -0
  387. package/dist/src/memory/store.js.map +1 -0
  388. package/dist/src/memory/textidentity.js +8 -0
  389. package/dist/src/memory/textidentity.js.map +1 -0
  390. package/dist/src/metrics.js +773 -0
  391. package/dist/src/metrics.js.map +1 -0
  392. package/dist/src/missingconfig.js +8 -0
  393. package/dist/src/missingconfig.js.map +1 -0
  394. package/dist/src/npmverbs.js +226 -0
  395. package/dist/src/npmverbs.js.map +1 -0
  396. package/dist/src/onboard/choices.js +191 -0
  397. package/dist/src/onboard/choices.js.map +1 -0
  398. package/dist/src/onboard/engine.js +344 -0
  399. package/dist/src/onboard/engine.js.map +1 -0
  400. package/dist/src/onboard/launch.js +83 -0
  401. package/dist/src/onboard/launch.js.map +1 -0
  402. package/dist/src/onboard/steps/appslug.js +211 -0
  403. package/dist/src/onboard/steps/appslug.js.map +1 -0
  404. package/dist/src/onboard/steps/bringup.js +408 -0
  405. package/dist/src/onboard/steps/bringup.js.map +1 -0
  406. package/dist/src/onboard/steps/compose.js +343 -0
  407. package/dist/src/onboard/steps/compose.js.map +1 -0
  408. package/dist/src/onboard/steps/configdelivery.js +50 -0
  409. package/dist/src/onboard/steps/configdelivery.js.map +1 -0
  410. package/dist/src/onboard/steps/configfill.js +1148 -0
  411. package/dist/src/onboard/steps/configfill.js.map +1 -0
  412. package/dist/src/onboard/steps/deploysh.js +80 -0
  413. package/dist/src/onboard/steps/deploysh.js.map +1 -0
  414. package/dist/src/onboard/steps/embeddings.js +472 -0
  415. package/dist/src/onboard/steps/embeddings.js.map +1 -0
  416. package/dist/src/onboard/steps/escalation.js +571 -0
  417. package/dist/src/onboard/steps/escalation.js.map +1 -0
  418. package/dist/src/onboard/steps/githubapp.js +1092 -0
  419. package/dist/src/onboard/steps/githubapp.js.map +1 -0
  420. package/dist/src/onboard/steps/golive.js +506 -0
  421. package/dist/src/onboard/steps/golive.js.map +1 -0
  422. package/dist/src/onboard/steps/index.js +67 -0
  423. package/dist/src/onboard/steps/index.js.map +1 -0
  424. package/dist/src/onboard/steps/ingress.js +762 -0
  425. package/dist/src/onboard/steps/ingress.js.map +1 -0
  426. package/dist/src/onboard/steps/inventory.js +420 -0
  427. package/dist/src/onboard/steps/inventory.js.map +1 -0
  428. package/dist/src/onboard/steps/llmauth.js +893 -0
  429. package/dist/src/onboard/steps/llmauth.js.map +1 -0
  430. package/dist/src/onboard/steps/memory.js +1060 -0
  431. package/dist/src/onboard/steps/memory.js.map +1 -0
  432. package/dist/src/onboard/steps/memorykeys.js +43 -0
  433. package/dist/src/onboard/steps/memorykeys.js.map +1 -0
  434. package/dist/src/onboard/steps/preflight.js +172 -0
  435. package/dist/src/onboard/steps/preflight.js.map +1 -0
  436. package/dist/src/onboard/steps/proof.js +502 -0
  437. package/dist/src/onboard/steps/proof.js.map +1 -0
  438. package/dist/src/onboard/steps/ssh.js +300 -0
  439. package/dist/src/onboard/steps/ssh.js.map +1 -0
  440. package/dist/src/onboard/steps/topology.js +291 -0
  441. package/dist/src/onboard/steps/topology.js.map +1 -0
  442. package/dist/src/onboard/steps/transport.js +511 -0
  443. package/dist/src/onboard/steps/transport.js.map +1 -0
  444. package/dist/src/onboard/steps/verifyup.js +362 -0
  445. package/dist/src/onboard/steps/verifyup.js.map +1 -0
  446. package/dist/src/onboard/steps/vmdeploy.js +368 -0
  447. package/dist/src/onboard/steps/vmdeploy.js.map +1 -0
  448. package/dist/src/onboard/toml.js +53 -0
  449. package/dist/src/onboard/toml.js.map +1 -0
  450. package/dist/src/opencli.js +508 -0
  451. package/dist/src/opencli.js.map +1 -0
  452. package/dist/src/openpr.js +457 -0
  453. package/dist/src/openpr.js.map +1 -0
  454. package/dist/src/openviking/client.js +821 -0
  455. package/dist/src/openviking/client.js.map +1 -0
  456. package/dist/src/openviking/context.js +218 -0
  457. package/dist/src/openviking/context.js.map +1 -0
  458. package/dist/src/openviking/embedder.js +457 -0
  459. package/dist/src/openviking/embedder.js.map +1 -0
  460. package/dist/src/openviking/gapsink.js +38 -0
  461. package/dist/src/openviking/gapsink.js.map +1 -0
  462. package/dist/src/openviking/health.js +69 -0
  463. package/dist/src/openviking/health.js.map +1 -0
  464. package/dist/src/openviking/index.js +24 -0
  465. package/dist/src/openviking/index.js.map +1 -0
  466. package/dist/src/openviking/lessonfind.js +54 -0
  467. package/dist/src/openviking/lessonfind.js.map +1 -0
  468. package/dist/src/openviking/probe.js +89 -0
  469. package/dist/src/openviking/probe.js.map +1 -0
  470. package/dist/src/openviking/proc.js +95 -0
  471. package/dist/src/openviking/proc.js.map +1 -0
  472. package/dist/src/openviking/provisionreport.js +144 -0
  473. package/dist/src/openviking/provisionreport.js.map +1 -0
  474. package/dist/src/openviking/reembed.js +317 -0
  475. package/dist/src/openviking/reembed.js.map +1 -0
  476. package/dist/src/openviking/relayout.js +153 -0
  477. package/dist/src/openviking/relayout.js.map +1 -0
  478. package/dist/src/openviking/sidecar-main.js +39 -0
  479. package/dist/src/openviking/sidecar-main.js.map +1 -0
  480. package/dist/src/openviking/sidecar.js +79 -0
  481. package/dist/src/openviking/sidecar.js.map +1 -0
  482. package/dist/src/openviking/store.js +1758 -0
  483. package/dist/src/openviking/store.js.map +1 -0
  484. package/dist/src/openviking/supervisor.js +422 -0
  485. package/dist/src/openviking/supervisor.js.map +1 -0
  486. package/dist/src/openviking/types.js +5 -0
  487. package/dist/src/openviking/types.js.map +1 -0
  488. package/dist/src/operator-recovery.js +172 -0
  489. package/dist/src/operator-recovery.js.map +1 -0
  490. package/dist/src/operatormessage.js +44 -0
  491. package/dist/src/operatormessage.js.map +1 -0
  492. package/dist/src/outcomes.js +1361 -0
  493. package/dist/src/outcomes.js.map +1 -0
  494. package/dist/src/piauthcopy.js +5 -0
  495. package/dist/src/piauthcopy.js.map +1 -0
  496. package/dist/src/picli.js +45 -0
  497. package/dist/src/picli.js.map +1 -0
  498. package/dist/src/picwd.js +25 -0
  499. package/dist/src/picwd.js.map +1 -0
  500. package/dist/src/pilogin.js +35 -0
  501. package/dist/src/pilogin.js.map +1 -0
  502. package/dist/src/pingpong.js +1028 -0
  503. package/dist/src/pingpong.js.map +1 -0
  504. package/dist/src/posting-journal.js +441 -0
  505. package/dist/src/posting-journal.js.map +1 -0
  506. package/dist/src/posting-outbox.js +662 -0
  507. package/dist/src/posting-outbox.js.map +1 -0
  508. package/dist/src/posting-receipt.js +203 -0
  509. package/dist/src/posting-receipt.js.map +1 -0
  510. package/dist/src/posting.js +348 -0
  511. package/dist/src/posting.js.map +1 -0
  512. package/dist/src/postops.js +637 -0
  513. package/dist/src/postops.js.map +1 -0
  514. package/dist/src/pr-activity.js +11 -0
  515. package/dist/src/pr-activity.js.map +1 -0
  516. package/dist/src/pr-author.js +5 -0
  517. package/dist/src/pr-author.js.map +1 -0
  518. package/dist/src/pr-conversation.js +355 -0
  519. package/dist/src/pr-conversation.js.map +1 -0
  520. package/dist/src/pr-session-lifecycle.js +542 -0
  521. package/dist/src/pr-session-lifecycle.js.map +1 -0
  522. package/dist/src/preflight.js +341 -0
  523. package/dist/src/preflight.js.map +1 -0
  524. package/dist/src/priorresolve.js +275 -0
  525. package/dist/src/priorresolve.js.map +1 -0
  526. package/dist/src/qcrbin.js +180 -0
  527. package/dist/src/qcrbin.js.map +1 -0
  528. package/dist/src/recheck.js +1398 -0
  529. package/dist/src/recheck.js.map +1 -0
  530. package/dist/src/reconcile.js +820 -0
  531. package/dist/src/reconcile.js.map +1 -0
  532. package/dist/src/recordedfindings.js +15 -0
  533. package/dist/src/recordedfindings.js.map +1 -0
  534. package/dist/src/regression.js +546 -0
  535. package/dist/src/regression.js.map +1 -0
  536. package/dist/src/replay.js +598 -0
  537. package/dist/src/replay.js.map +1 -0
  538. package/dist/src/requiredpasses.js +113 -0
  539. package/dist/src/requiredpasses.js.map +1 -0
  540. package/dist/src/resumecheck.js +168 -0
  541. package/dist/src/resumecheck.js.map +1 -0
  542. package/dist/src/reviewcli.js +671 -0
  543. package/dist/src/reviewcli.js.map +1 -0
  544. package/dist/src/reviewcontext.js +22 -0
  545. package/dist/src/reviewcontext.js.map +1 -0
  546. package/dist/src/reviewdetach.js +574 -0
  547. package/dist/src/reviewdetach.js.map +1 -0
  548. package/dist/src/reviewhistory.js +284 -0
  549. package/dist/src/reviewhistory.js.map +1 -0
  550. package/dist/src/reviewhome.js +26 -0
  551. package/dist/src/reviewhome.js.map +1 -0
  552. package/dist/src/reviewmemory.js +110 -0
  553. package/dist/src/reviewmemory.js.map +1 -0
  554. package/dist/src/reviewrendercli.js +104 -0
  555. package/dist/src/reviewrendercli.js.map +1 -0
  556. package/dist/src/round-work.js +20 -0
  557. package/dist/src/round-work.js.map +1 -0
  558. package/dist/src/runhost.js +72 -0
  559. package/dist/src/runhost.js.map +1 -0
  560. package/dist/src/scanauth.js +25 -0
  561. package/dist/src/scanauth.js.map +1 -0
  562. package/dist/src/scanbox.js +846 -0
  563. package/dist/src/scanbox.js.map +1 -0
  564. package/dist/src/scancli.js +1074 -0
  565. package/dist/src/scancli.js.map +1 -0
  566. package/dist/src/scandriverlog.js +30 -0
  567. package/dist/src/scandriverlog.js.map +1 -0
  568. package/dist/src/session-bridge.js +75 -0
  569. package/dist/src/session-bridge.js.map +1 -0
  570. package/dist/src/session-command-payload.js +29 -0
  571. package/dist/src/session-command-payload.js.map +1 -0
  572. package/dist/src/session-command-supervisor.js +939 -0
  573. package/dist/src/session-command-supervisor.js.map +1 -0
  574. package/dist/src/sessionjsonl.js +85 -0
  575. package/dist/src/sessionjsonl.js.map +1 -0
  576. package/dist/src/sessions.js +541 -0
  577. package/dist/src/sessions.js.map +1 -0
  578. package/dist/src/setup/adapters.js +330 -0
  579. package/dist/src/setup/adapters.js.map +1 -0
  580. package/dist/src/setup/baselines.js +64 -0
  581. package/dist/src/setup/baselines.js.map +1 -0
  582. package/dist/src/setup/caserunner.js +554 -0
  583. package/dist/src/setup/caserunner.js.map +1 -0
  584. package/dist/src/setup/configcommit.js +358 -0
  585. package/dist/src/setup/configcommit.js.map +1 -0
  586. package/dist/src/setup/engine.js +672 -0
  587. package/dist/src/setup/engine.js.map +1 -0
  588. package/dist/src/setup/facts.js +593 -0
  589. package/dist/src/setup/facts.js.map +1 -0
  590. package/dist/src/setup/findings.js +948 -0
  591. package/dist/src/setup/findings.js.map +1 -0
  592. package/dist/src/setup/history.js +338 -0
  593. package/dist/src/setup/history.js.map +1 -0
  594. package/dist/src/setup/interview.js +185 -0
  595. package/dist/src/setup/interview.js.map +1 -0
  596. package/dist/src/setup/ledger.js +207 -0
  597. package/dist/src/setup/ledger.js.map +1 -0
  598. package/dist/src/setup/pins.js +43 -0
  599. package/dist/src/setup/pins.js.map +1 -0
  600. package/dist/src/setup/portrait.js +432 -0
  601. package/dist/src/setup/portrait.js.map +1 -0
  602. package/dist/src/setup/presentation.js +9 -0
  603. package/dist/src/setup/presentation.js.map +1 -0
  604. package/dist/src/setup/profile.js +417 -0
  605. package/dist/src/setup/profile.js.map +1 -0
  606. package/dist/src/setup/replay.js +240 -0
  607. package/dist/src/setup/replay.js.map +1 -0
  608. package/dist/src/setup/replaybuild.js +311 -0
  609. package/dist/src/setup/replaybuild.js.map +1 -0
  610. package/dist/src/setup/replayrun.js +806 -0
  611. package/dist/src/setup/replayrun.js.map +1 -0
  612. package/dist/src/setup/replaysource.js +169 -0
  613. package/dist/src/setup/replaysource.js.map +1 -0
  614. package/dist/src/setup/retune.js +333 -0
  615. package/dist/src/setup/retune.js.map +1 -0
  616. package/dist/src/setup/retunelog.js +51 -0
  617. package/dist/src/setup/retunelog.js.map +1 -0
  618. package/dist/src/setup/scan.js +725 -0
  619. package/dist/src/setup/scan.js.map +1 -0
  620. package/dist/src/setup/scanbuild.js +133 -0
  621. package/dist/src/setup/scanbuild.js.map +1 -0
  622. package/dist/src/setup/scanfacts.js +96 -0
  623. package/dist/src/setup/scanfacts.js.map +1 -0
  624. package/dist/src/setup/scanlease.js +251 -0
  625. package/dist/src/setup/scanlease.js.map +1 -0
  626. package/dist/src/setup/scanreport.js +289 -0
  627. package/dist/src/setup/scanreport.js.map +1 -0
  628. package/dist/src/setup/scanrun.js +1733 -0
  629. package/dist/src/setup/scanrun.js.map +1 -0
  630. package/dist/src/setup/scantree.js +257 -0
  631. package/dist/src/setup/scantree.js.map +1 -0
  632. package/dist/src/setup/stage2.js +617 -0
  633. package/dist/src/setup/stage2.js.map +1 -0
  634. package/dist/src/setup/stage2request.js +259 -0
  635. package/dist/src/setup/stage2request.js.map +1 -0
  636. package/dist/src/setup/survey.js +307 -0
  637. package/dist/src/setup/survey.js.map +1 -0
  638. package/dist/src/setup/surveyrun.js +549 -0
  639. package/dist/src/setup/surveyrun.js.map +1 -0
  640. package/dist/src/setup/textsniff.js +89 -0
  641. package/dist/src/setup/textsniff.js.map +1 -0
  642. package/dist/src/setup/trackersink.js +395 -0
  643. package/dist/src/setup/trackersink.js.map +1 -0
  644. package/dist/src/setup/triage.js +636 -0
  645. package/dist/src/setup/triage.js.map +1 -0
  646. package/dist/src/setup/tuning.js +585 -0
  647. package/dist/src/setup/tuning.js.map +1 -0
  648. package/dist/src/setup/unitcut.js +437 -0
  649. package/dist/src/setup/unitcut.js.map +1 -0
  650. package/dist/src/singleflight.js +72 -0
  651. package/dist/src/singleflight.js.map +1 -0
  652. package/dist/src/slack/announce.js +725 -0
  653. package/dist/src/slack/announce.js.map +1 -0
  654. package/dist/src/slack/api.js +227 -0
  655. package/dist/src/slack/api.js.map +1 -0
  656. package/dist/src/slack/messages.js +158 -0
  657. package/dist/src/slack/messages.js.map +1 -0
  658. package/dist/src/slack/origin.js +550 -0
  659. package/dist/src/slack/origin.js.map +1 -0
  660. package/dist/src/slack/policy.js +225 -0
  661. package/dist/src/slack/policy.js.map +1 -0
  662. package/dist/src/slack/reply.js +153 -0
  663. package/dist/src/slack/reply.js.map +1 -0
  664. package/dist/src/slack/router.js +189 -0
  665. package/dist/src/slack/router.js.map +1 -0
  666. package/dist/src/slack/socket.js +323 -0
  667. package/dist/src/slack/socket.js.map +1 -0
  668. package/dist/src/slack/types.js +11 -0
  669. package/dist/src/slack/types.js.map +1 -0
  670. package/dist/src/sqlitehint.js +30 -0
  671. package/dist/src/sqlitehint.js.map +1 -0
  672. package/dist/src/ssh-observation.js +25 -0
  673. package/dist/src/ssh-observation.js.map +1 -0
  674. package/dist/src/state.js +5869 -0
  675. package/dist/src/state.js.map +1 -0
  676. package/dist/src/statemachine.js +220 -0
  677. package/dist/src/statemachine.js.map +1 -0
  678. package/dist/src/stubs.js +52 -0
  679. package/dist/src/stubs.js.map +1 -0
  680. package/dist/src/takeover.js +506 -0
  681. package/dist/src/takeover.js.map +1 -0
  682. package/dist/src/takeoverpi.js +249 -0
  683. package/dist/src/takeoverpi.js.map +1 -0
  684. package/dist/src/terminal-failure.js +26 -0
  685. package/dist/src/terminal-failure.js.map +1 -0
  686. package/dist/src/thread-resolution-refusal.js +4 -0
  687. package/dist/src/thread-resolution-refusal.js.map +1 -0
  688. package/dist/src/tmux.js +126 -0
  689. package/dist/src/tmux.js.map +1 -0
  690. package/dist/src/trackerid.js +43 -0
  691. package/dist/src/trackerid.js.map +1 -0
  692. package/dist/src/transcriptindex.js +512 -0
  693. package/dist/src/transcriptindex.js.map +1 -0
  694. package/dist/src/tui/actions.js +404 -0
  695. package/dist/src/tui/actions.js.map +1 -0
  696. package/dist/src/tui/alerts.js +523 -0
  697. package/dist/src/tui/alerts.js.map +1 -0
  698. package/dist/src/tui/app.js +1835 -0
  699. package/dist/src/tui/app.js.map +1 -0
  700. package/dist/src/tui/archiveops.js +164 -0
  701. package/dist/src/tui/archiveops.js.map +1 -0
  702. package/dist/src/tui/autofile.js +191 -0
  703. package/dist/src/tui/autofile.js.map +1 -0
  704. package/dist/src/tui/board.js +1143 -0
  705. package/dist/src/tui/board.js.map +1 -0
  706. package/dist/src/tui/candidates.js +699 -0
  707. package/dist/src/tui/candidates.js.map +1 -0
  708. package/dist/src/tui/cellwidth.js +151 -0
  709. package/dist/src/tui/cellwidth.js.map +1 -0
  710. package/dist/src/tui/changelog-store.js +404 -0
  711. package/dist/src/tui/changelog-store.js.map +1 -0
  712. package/dist/src/tui/chord.js +26 -0
  713. package/dist/src/tui/chord.js.map +1 -0
  714. package/dist/src/tui/clipboard.js +81 -0
  715. package/dist/src/tui/clipboard.js.map +1 -0
  716. package/dist/src/tui/cmdbar.js +253 -0
  717. package/dist/src/tui/cmdbar.js.map +1 -0
  718. package/dist/src/tui/companion.js +1275 -0
  719. package/dist/src/tui/companion.js.map +1 -0
  720. package/dist/src/tui/companionplan.js +200 -0
  721. package/dist/src/tui/companionplan.js.map +1 -0
  722. package/dist/src/tui/companiontab.js +61 -0
  723. package/dist/src/tui/companiontab.js.map +1 -0
  724. package/dist/src/tui/confighome.js +105 -0
  725. package/dist/src/tui/confighome.js.map +1 -0
  726. package/dist/src/tui/connect.js +44 -0
  727. package/dist/src/tui/connect.js.map +1 -0
  728. package/dist/src/tui/deploy-ceremony.js +75 -0
  729. package/dist/src/tui/deploy-ceremony.js.map +1 -0
  730. package/dist/src/tui/deploy-drain.js +93 -0
  731. package/dist/src/tui/deploy-drain.js.map +1 -0
  732. package/dist/src/tui/deploy-process.js +234 -0
  733. package/dist/src/tui/deploy-process.js.map +1 -0
  734. package/dist/src/tui/deploytab.js +1263 -0
  735. package/dist/src/tui/deploytab.js.map +1 -0
  736. package/dist/src/tui/design.js +111 -0
  737. package/dist/src/tui/design.js.map +1 -0
  738. package/dist/src/tui/digesttab.js +148 -0
  739. package/dist/src/tui/digesttab.js.map +1 -0
  740. package/dist/src/tui/emptystate.js +32 -0
  741. package/dist/src/tui/emptystate.js.map +1 -0
  742. package/dist/src/tui/evidence.js +790 -0
  743. package/dist/src/tui/evidence.js.map +1 -0
  744. package/dist/src/tui/feed.js +415 -0
  745. package/dist/src/tui/feed.js.map +1 -0
  746. package/dist/src/tui/feedbacktab.js +907 -0
  747. package/dist/src/tui/feedbacktab.js.map +1 -0
  748. package/dist/src/tui/filters.js +72 -0
  749. package/dist/src/tui/filters.js.map +1 -0
  750. package/dist/src/tui/ghread.js +272 -0
  751. package/dist/src/tui/ghread.js.map +1 -0
  752. package/dist/src/tui/historypull.js +61 -0
  753. package/dist/src/tui/historypull.js.map +1 -0
  754. package/dist/src/tui/inboxpull.js +197 -0
  755. package/dist/src/tui/inboxpull.js.map +1 -0
  756. package/dist/src/tui/index.js +1425 -0
  757. package/dist/src/tui/index.js.map +1 -0
  758. package/dist/src/tui/issuesink.js +206 -0
  759. package/dist/src/tui/issuesink.js.map +1 -0
  760. package/dist/src/tui/jsonfile.js +32 -0
  761. package/dist/src/tui/jsonfile.js.map +1 -0
  762. package/dist/src/tui/keys.js +97 -0
  763. package/dist/src/tui/keys.js.map +1 -0
  764. package/dist/src/tui/layout.js +70 -0
  765. package/dist/src/tui/layout.js.map +1 -0
  766. package/dist/src/tui/learning.js +469 -0
  767. package/dist/src/tui/learning.js.map +1 -0
  768. package/dist/src/tui/lessonswitch.js +103 -0
  769. package/dist/src/tui/lessonswitch.js.map +1 -0
  770. package/dist/src/tui/livecontrol.js +167 -0
  771. package/dist/src/tui/livecontrol.js.map +1 -0
  772. package/dist/src/tui/memforward.js +310 -0
  773. package/dist/src/tui/memforward.js.map +1 -0
  774. package/dist/src/tui/memincident.js +287 -0
  775. package/dist/src/tui/memincident.js.map +1 -0
  776. package/dist/src/tui/memory.js +485 -0
  777. package/dist/src/tui/memory.js.map +1 -0
  778. package/dist/src/tui/memtab.js +513 -0
  779. package/dist/src/tui/memtab.js.map +1 -0
  780. package/dist/src/tui/metricstab.js +979 -0
  781. package/dist/src/tui/metricstab.js.map +1 -0
  782. package/dist/src/tui/model.js +104 -0
  783. package/dist/src/tui/model.js.map +1 -0
  784. package/dist/src/tui/mouse.js +83 -0
  785. package/dist/src/tui/mouse.js.map +1 -0
  786. package/dist/src/tui/msg.js +196 -0
  787. package/dist/src/tui/msg.js.map +1 -0
  788. package/dist/src/tui/nativecompanion.js +321 -0
  789. package/dist/src/tui/nativecompanion.js.map +1 -0
  790. package/dist/src/tui/openurl.js +17 -0
  791. package/dist/src/tui/openurl.js.map +1 -0
  792. package/dist/src/tui/paint.js +501 -0
  793. package/dist/src/tui/paint.js.map +1 -0
  794. package/dist/src/tui/panes.js +74 -0
  795. package/dist/src/tui/panes.js.map +1 -0
  796. package/dist/src/tui/pipane.js +166 -0
  797. package/dist/src/tui/pipane.js.map +1 -0
  798. package/dist/src/tui/poll-hooks.js +11 -0
  799. package/dist/src/tui/poll-hooks.js.map +1 -0
  800. package/dist/src/tui/poll.js +113 -0
  801. package/dist/src/tui/poll.js.map +1 -0
  802. package/dist/src/tui/proposals.js +715 -0
  803. package/dist/src/tui/proposals.js.map +1 -0
  804. package/dist/src/tui/prpause.js +132 -0
  805. package/dist/src/tui/prpause.js.map +1 -0
  806. package/dist/src/tui/reload.js +351 -0
  807. package/dist/src/tui/reload.js.map +1 -0
  808. package/dist/src/tui/remote.js +312 -0
  809. package/dist/src/tui/remote.js.map +1 -0
  810. package/dist/src/tui/rollover.js +767 -0
  811. package/dist/src/tui/rollover.js.map +1 -0
  812. package/dist/src/tui/scantab.js +1053 -0
  813. package/dist/src/tui/scantab.js.map +1 -0
  814. package/dist/src/tui/setupentry.js +81 -0
  815. package/dist/src/tui/setupentry.js.map +1 -0
  816. package/dist/src/tui/sidebar.js +602 -0
  817. package/dist/src/tui/sidebar.js.map +1 -0
  818. package/dist/src/tui/sshtriage.js +393 -0
  819. package/dist/src/tui/sshtriage.js.map +1 -0
  820. package/dist/src/tui/startup.js +172 -0
  821. package/dist/src/tui/startup.js.map +1 -0
  822. package/dist/src/tui/tabs.js +41 -0
  823. package/dist/src/tui/tabs.js.map +1 -0
  824. package/dist/src/tui/termmirror.js +217 -0
  825. package/dist/src/tui/termmirror.js.map +1 -0
  826. package/dist/src/tui/theme.js +95 -0
  827. package/dist/src/tui/theme.js.map +1 -0
  828. package/dist/src/tui/ticketstab.js +224 -0
  829. package/dist/src/tui/ticketstab.js.map +1 -0
  830. package/dist/src/tui/tmuxsocket.js +101 -0
  831. package/dist/src/tui/tmuxsocket.js.map +1 -0
  832. package/dist/src/tui/trackertickets.js +77 -0
  833. package/dist/src/tui/trackertickets.js.map +1 -0
  834. package/dist/src/tui/unwedge.js +245 -0
  835. package/dist/src/tui/unwedge.js.map +1 -0
  836. package/dist/src/tui/viewer.js +479 -0
  837. package/dist/src/tui/viewer.js.map +1 -0
  838. package/dist/src/tui/viewerinput.js +125 -0
  839. package/dist/src/tui/viewerinput.js.map +1 -0
  840. package/dist/src/updatenotice.js +143 -0
  841. package/dist/src/updatenotice.js.map +1 -0
  842. package/dist/src/usage.js +1007 -0
  843. package/dist/src/usage.js.map +1 -0
  844. package/dist/src/verdicts.js +3848 -0
  845. package/dist/src/verdicts.js.map +1 -0
  846. package/dist/src/version.js +58 -0
  847. package/dist/src/version.js.map +1 -0
  848. package/dist/src/wakes.js +411 -0
  849. package/dist/src/wakes.js.map +1 -0
  850. package/dist/src/webhook.js +725 -0
  851. package/dist/src/webhook.js.map +1 -0
  852. package/dist/src/webhookheal.js +238 -0
  853. package/dist/src/webhookheal.js.map +1 -0
  854. package/dist/src/wire.js +1801 -0
  855. package/dist/src/wire.js.map +1 -0
  856. package/dist/src/worker-session-host.js +531 -0
  857. package/dist/src/worker-session-host.js.map +1 -0
  858. package/dist/src/workerbreaker.js +112 -0
  859. package/dist/src/workerbreaker.js.map +1 -0
  860. package/dist/src/workercontrol.js +49 -0
  861. package/dist/src/workercontrol.js.map +1 -0
  862. package/dist/src/workerlease.js +351 -0
  863. package/dist/src/workerlease.js.map +1 -0
  864. package/dist/src/workerliveness.js +84 -0
  865. package/dist/src/workerliveness.js.map +1 -0
  866. package/dist/src/workerlog.js +65 -0
  867. package/dist/src/workerlog.js.map +1 -0
  868. package/dist/src/workerruntime.js +10 -0
  869. package/dist/src/workerruntime.js.map +1 -0
  870. package/dist/src/workersupervisor.js +1206 -0
  871. package/dist/src/workersupervisor.js.map +1 -0
  872. package/dist/src/workerusage.js +23 -0
  873. package/dist/src/workerusage.js.map +1 -0
  874. package/dist/src/workerworld.js +332 -0
  875. package/dist/src/workerworld.js.map +1 -0
  876. package/dist/src/worktrees.js +984 -0
  877. package/dist/src/worktrees.js.map +1 -0
  878. package/docker/Dockerfile +284 -0
  879. package/docker/Dockerfile.dockerignore +35 -0
  880. package/docker/README.md +221 -0
  881. package/docker/companion/Dockerfile +139 -0
  882. package/docker/companion/agents/evidence.md +34 -0
  883. package/docker/companion/agents/explore.md +26 -0
  884. package/docker/companion/agents/pass-survey.md +49 -0
  885. package/docker/companion/agents/study.md +26 -0
  886. package/docker/companion/entrypoint.sh +343 -0
  887. package/docker/companion/memory-health.mjs +269 -0
  888. package/docker/entrypoint.sh +782 -0
  889. package/docker/memory/Dockerfile +191 -0
  890. package/docker/memory/Dockerfile.dockerignore +20 -0
  891. package/docker/memory/README.md +60 -0
  892. package/docker/memory/entrypoint.sh +163 -0
  893. package/docker/setid/qcr-setid.c +109 -0
  894. package/docker/tunnel/Dockerfile.cloudflared +51 -0
  895. package/docker/tunnel/Dockerfile.ngrok +40 -0
  896. package/docker/tunnel/sidecar.mjs +411 -0
  897. package/docker/vm/tmux.conf +26 -0
  898. package/docker-compose.yml +348 -0
  899. package/extensions/cli/bash-guard-ambient.ts +71 -0
  900. package/extensions/cli/bash-guard.ts +12 -0
  901. package/extensions/cli/companion-guard.ts +8 -0
  902. package/extensions/cli/debug-round.ts +9 -0
  903. package/extensions/cli/inject-bridge.ts +8 -0
  904. package/extensions/cli/ledger-pin.ts +13 -0
  905. package/extensions/cli/lens.ts +22 -0
  906. package/extensions/cli/muted-theme.ts +9 -0
  907. package/extensions/cli/onboarding.ts +8 -0
  908. package/extensions/cli/setup.ts +8 -0
  909. package/extensions/cli/tui-view.ts +8 -0
  910. package/extensions/companion-guard.ts +411 -0
  911. package/extensions/debug-round.ts +281 -0
  912. package/extensions/inject-bridge.ts +630 -0
  913. package/extensions/inline-bash.ts +102 -0
  914. package/extensions/muted-theme.json +68 -0
  915. package/extensions/muted-theme.ts +23 -0
  916. package/extensions/onboarding.ts +233 -0
  917. package/extensions/setup-replay.ts +336 -0
  918. package/extensions/setup-scan.ts +1236 -0
  919. package/extensions/setup-triage.ts +190 -0
  920. package/extensions/setup.ts +1428 -0
  921. package/extensions/tui-view.ts +489 -0
  922. package/extensions/vendor/openviking-pi/LICENSE +201 -0
  923. package/extensions/vendor/openviking-pi/NOTICE +68 -0
  924. package/extensions/vendor/openviking-pi/README.md +550 -0
  925. package/extensions/vendor/openviking-pi/client.ts +588 -0
  926. package/extensions/vendor/openviking-pi/config.json +28 -0
  927. package/extensions/vendor/openviking-pi/config.ts +271 -0
  928. package/extensions/vendor/openviking-pi/index.ts +523 -0
  929. package/extensions/vendor/openviking-pi/lib/capture-adapter.d.mts +10 -0
  930. package/extensions/vendor/openviking-pi/lib/capture-adapter.mjs +88 -0
  931. package/extensions/vendor/openviking-pi/lib/takeover-core.d.mts +80 -0
  932. package/extensions/vendor/openviking-pi/lib/takeover-core.mjs +406 -0
  933. package/extensions/vendor/openviking-pi/lib/uri-guard-adapter.d.mts +1 -0
  934. package/extensions/vendor/openviking-pi/lib/uri-guard-adapter.mjs +42 -0
  935. package/extensions/vendor/openviking-pi/patches/0000-vendoring-and-build-conformance.patch +726 -0
  936. package/extensions/vendor/openviking-pi/patches/0001-remove-session-before-compact-handler.patch +101 -0
  937. package/extensions/vendor/openviking-pi/patches/0002-no-ambient-work-in-subagent-leaves.patch +202 -0
  938. package/extensions/vendor/openviking-pi/patches/0003-never-auto-create-openviking-sessions.patch +120 -0
  939. package/extensions/vendor/openviking-pi/patches/0004-viking-write-durable-batch-write.patch +521 -0
  940. package/extensions/vendor/openviking-pi/patches/0005-second-memory-namespace.patch +786 -0
  941. package/extensions/vendor/openviking-pi/patches/0006-writes-that-stick-and-honest-errors.patch +996 -0
  942. package/extensions/vendor/openviking-pi/patches/0007-bounded-recall-no-commit.patch +794 -0
  943. package/extensions/vendor/openviking-pi/patches/0008-pr-derived-recall.patch +379 -0
  944. package/extensions/vendor/openviking-pi/patches/0009-pr-session-tools-in-round-areas.patch +375 -0
  945. package/extensions/vendor/openviking-pi/patches/0010-typed-lessons.patch +448 -0
  946. package/extensions/vendor/openviking-pi/patches/0011-review-session-memory-boundary.patch +382 -0
  947. package/extensions/vendor/openviking-pi/patches/0012-typecheck-against-the-real-pi.patch +129 -0
  948. package/extensions/vendor/openviking-pi/patches/0013-createopenviking-factory.patch +1168 -0
  949. package/extensions/vendor/openviking-pi/qcr-hint.ts +313 -0
  950. package/extensions/vendor/openviking-pi/qcr-honest.ts +183 -0
  951. package/extensions/vendor/openviking-pi/qcr-hooks.ts +87 -0
  952. package/extensions/vendor/openviking-pi/qcr-leaf.ts +78 -0
  953. package/extensions/vendor/openviking-pi/qcr-lesson.ts +231 -0
  954. package/extensions/vendor/openviking-pi/qcr-namespaces.ts +198 -0
  955. package/extensions/vendor/openviking-pi/qcr-recall.ts +288 -0
  956. package/extensions/vendor/openviking-pi/qcr-shim.ts +142 -0
  957. package/extensions/vendor/openviking-pi/qcr-write.ts +427 -0
  958. package/extensions/vendor/openviking-pi/recall.ts +149 -0
  959. package/extensions/vendor/openviking-pi/shared/capture-utils.d.mts +9 -0
  960. package/extensions/vendor/openviking-pi/shared/capture-utils.mjs +515 -0
  961. package/extensions/vendor/openviking-pi/shared/credentials.d.mts +14 -0
  962. package/extensions/vendor/openviking-pi/shared/credentials.mjs +228 -0
  963. package/extensions/vendor/openviking-pi/shared/pending-queue.d.mts +19 -0
  964. package/extensions/vendor/openviking-pi/shared/pending-queue.mjs +458 -0
  965. package/extensions/vendor/openviking-pi/shared/profile-inject.d.mts +17 -0
  966. package/extensions/vendor/openviking-pi/shared/profile-inject.mjs +294 -0
  967. package/extensions/vendor/openviking-pi/shared/recall-compress-core.mjs +195 -0
  968. package/extensions/vendor/openviking-pi/shared/recall-core.d.mts +13 -0
  969. package/extensions/vendor/openviking-pi/shared/recall-core.mjs +609 -0
  970. package/extensions/vendor/openviking-pi/shared/retryable.mjs +9 -0
  971. package/extensions/vendor/openviking-pi/shared/session-model.d.mts +3 -0
  972. package/extensions/vendor/openviking-pi/shared/session-model.mjs +57 -0
  973. package/extensions/vendor/openviking-pi/shared/uri-guard.mjs +56 -0
  974. package/extensions/vendor/openviking-pi/shared/workspace-peer.d.mts +5 -0
  975. package/extensions/vendor/openviking-pi/shared/workspace-peer.mjs +16 -0
  976. package/extensions/vendor/openviking-pi/sync.ts +163 -0
  977. package/extensions/vendor/openviking-pi/takeover.ts +36 -0
  978. package/extensions/vendor/openviking-pi/tools.ts +479 -0
  979. package/extensions/vendor/openviking-pi/upstream.json +48 -0
  980. package/package.json +138 -4
  981. package/profiles/default/README.md +21 -0
  982. package/profiles/default/addenda/.gitkeep +0 -0
  983. package/profiles/default/profile.toml +17 -0
  984. package/profiles/example-django/README.md +21 -0
  985. package/profiles/example-django/addenda/10-migration-discipline.md +13 -0
  986. package/profiles/example-django/addenda/20-new-column-nullability.md +12 -0
  987. package/profiles/example-django/addenda/30-test-doctrine.md +12 -0
  988. package/profiles/example-django/addenda/40-orm-usage.md +19 -0
  989. package/profiles/example-django/addenda/50-declared-shape.md +10 -0
  990. package/profiles/example-django/addenda/60-config-placement.md +14 -0
  991. package/profiles/example-django/heuristics.toml +24 -0
  992. package/profiles/example-django/profile.toml +9 -0
  993. package/profiles/fast/README.md +24 -0
  994. package/profiles/fast/profile.toml +59 -0
  995. package/profiles/minimal/README.md +17 -0
  996. package/profiles/minimal/addenda/.gitkeep +0 -0
  997. package/profiles/minimal/profile.toml +8 -0
  998. package/profiles/snappy/README.md +24 -0
  999. package/profiles/snappy/addenda/10-race-as-question.md +6 -0
  1000. package/profiles/snappy/profile.toml +46 -0
  1001. package/prompts/companion-day-open.md +46 -0
  1002. package/prompts/companion-first-run.md +104 -0
  1003. package/prompts/companion.md +821 -0
  1004. package/prompts/conversation-system.md +117 -0
  1005. package/prompts/eod-sweep.md +120 -0
  1006. package/prompts/onboarding.md +74 -0
  1007. package/prompts/pass-common.md +52 -0
  1008. package/prompts/pass-quality-common.md +22 -0
  1009. package/prompts/round-first.md +874 -0
  1010. package/prompts/round-follow-up.md +991 -0
  1011. package/prompts/round-re-review.md +889 -0
  1012. package/prompts/round-recheck.md +196 -0
  1013. package/prompts/round-staleness.md +856 -0
  1014. package/schemas/review-result.v1.json +391 -0
  1015. package/schemas/scan-result.v1.json +421 -0
  1016. package/schemas/version.v1.json +57 -0
  1017. package/scripts/approve-pr.sh +16 -0
  1018. package/scripts/build-stamp.mjs +67 -0
  1019. package/scripts/commit-verdict.sh +155 -0
  1020. package/scripts/companion-e2e.sh +250 -0
  1021. package/scripts/companion-memory-forward.mjs +1966 -0
  1022. package/scripts/config-fingerprint.sh +28 -0
  1023. package/scripts/deploy-manifest.mjs +141 -0
  1024. package/scripts/deploy.sh +1435 -0
  1025. package/scripts/directory-lock.mjs +193 -0
  1026. package/scripts/heartbeat-fresh.mjs +54 -0
  1027. package/scripts/install-locator.sh +328 -0
  1028. package/scripts/install-wrapper.sh +76 -0
  1029. package/scripts/memory-search-check.mjs +98 -0
  1030. package/scripts/mint-token.sh +212 -0
  1031. package/scripts/openviking-embedder.py +392 -0
  1032. package/scripts/openviking-ov-conf.mjs +161 -0
  1033. package/scripts/openviking-provision.mjs +1122 -0
  1034. package/scripts/openviking-reembed.mjs +1154 -0
  1035. package/scripts/post-review.sh +16 -0
  1036. package/scripts/pr-checks.sh +256 -0
  1037. package/scripts/pr-context.py +174 -0
  1038. package/scripts/pr-context.sh +63 -0
  1039. package/scripts/pr-self.sh +144 -0
  1040. package/scripts/pr-threads.sh +145 -0
  1041. package/scripts/qcr +15 -0
  1042. package/scripts/qcr-host.sh +769 -0
  1043. package/scripts/render-review.sh +24 -0
  1044. package/scripts/reply-thread.sh +16 -0
  1045. package/scripts/required-passes.py +112 -0
  1046. package/scripts/smoke-companion.sh +211 -0
  1047. package/scripts/tui-deploy-runner.mjs +61 -0
  1048. package/scripts/verify-dist.mjs +201 -0
  1049. package/scripts/vm-ghcr-login.sh +188 -0
  1050. package/seeds/agents/pass-baseline.md +61 -0
  1051. package/seeds/agents/pass-contracts.md +30 -0
  1052. package/seeds/agents/pass-data-safety.md +54 -0
  1053. package/seeds/agents/pass-delivery.md +37 -0
  1054. package/seeds/agents/pass-prod-risk.md +24 -0
  1055. package/seeds/agents/pass-security.md +31 -0
  1056. package/seeds/agents/pass-statelessness.md +27 -0
  1057. package/seeds/agents/pass-ui.md +23 -0
  1058. package/seeds/agents/pass-validate.md +50 -0
  1059. package/seeds/prompts/conversation-system.md +117 -0
  1060. package/seeds/prompts/eod-sweep.md +120 -0
  1061. package/seeds/prompts/pass-common.md +52 -0
  1062. package/skills/companion/adjudicate/SKILL.md +247 -0
  1063. package/skills/companion/evidence/SKILL.md +150 -0
  1064. package/skills/companion/land/SKILL.md +200 -0
  1065. package/skills/companion/replay/SKILL.md +138 -0
  1066. package/skills/companion/setup/SKILL.md +167 -0
  1067. package/skills/companion/survey/SKILL.md +160 -0
  1068. package/skills/selfimprove/README.md +34 -0
  1069. package/skills/selfimprove/SKILL.md +127 -0
  1070. package/skills/selfimprove/agents/openai.yaml +2 -0
  1071. package/skills/selfimprove/commands/selfimprove.md +6 -0
  1072. package/skills/selfimprove/references/fix-loop.md +49 -0
  1073. package/skills/selfimprove/references/ledger.md +20 -0
  1074. package/skills/selfimprove/references/setup.md +40 -0
  1075. package/src/anomalies.ts +566 -0
  1076. package/src/answerworker.ts +251 -0
  1077. package/src/appstamp.ts +65 -0
  1078. package/src/archive/admission.ts +3 -0
  1079. package/src/archive/archivedb.ts +548 -0
  1080. package/src/archive/archiver.ts +1963 -0
  1081. package/src/archive/archivewrite.ts +279 -0
  1082. package/src/archive/bundle.ts +333 -0
  1083. package/src/archive/dbmove.ts +911 -0
  1084. package/src/archive/duplicatecounts.ts +98 -0
  1085. package/src/archive/eligibility.ts +181 -0
  1086. package/src/archive/extract.ts +342 -0
  1087. package/src/archive/fsutil.ts +415 -0
  1088. package/src/archive/gzfile.ts +370 -0
  1089. package/src/archive/kinds.ts +21 -0
  1090. package/src/archive/livecheckpoint.ts +217 -0
  1091. package/src/archive/liveretention.ts +180 -0
  1092. package/src/archive/manifest.ts +519 -0
  1093. package/src/archive/overseer.ts +336 -0
  1094. package/src/archive/piglobal.ts +174 -0
  1095. package/src/archive/plan.ts +612 -0
  1096. package/src/archive/prarchive.ts +984 -0
  1097. package/src/archive/prfiles.ts +406 -0
  1098. package/src/archive/report.ts +252 -0
  1099. package/src/archive/restore.ts +330 -0
  1100. package/src/archive/rows.ts +187 -0
  1101. package/src/archive/seal.ts +630 -0
  1102. package/src/archive/status.ts +719 -0
  1103. package/src/archive/storepass.ts +581 -0
  1104. package/src/backfill.ts +362 -0
  1105. package/src/bench/cost.ts +113 -0
  1106. package/src/bench/exec.ts +90 -0
  1107. package/src/bench/values.ts +13 -0
  1108. package/src/botcontrol.ts +176 -0
  1109. package/src/botworker.ts +953 -0
  1110. package/src/capture.ts +321 -0
  1111. package/src/cases.ts +1789 -0
  1112. package/src/channelfs.ts +26 -0
  1113. package/src/checklist.ts +506 -0
  1114. package/src/ciretry.ts +141 -0
  1115. package/src/cli.ts +2271 -0
  1116. package/src/cliops.ts +384 -0
  1117. package/src/clonedir.ts +15 -0
  1118. package/src/commandeffects.ts +57 -0
  1119. package/src/commands.ts +1678 -0
  1120. package/src/companioninbox.ts +239 -0
  1121. package/src/compare.ts +957 -0
  1122. package/src/config.ts +2050 -0
  1123. package/src/configcheck.ts +133 -0
  1124. package/src/coreext.ts +47 -0
  1125. package/src/daemon.ts +1302 -0
  1126. package/src/debuground.ts +927 -0
  1127. package/src/debugroundpi.ts +262 -0
  1128. package/src/diagnostics.ts +14 -0
  1129. package/src/digest.ts +183 -0
  1130. package/src/dispatch.ts +2250 -0
  1131. package/src/engine/answerguard.ts +27 -0
  1132. package/src/engine/botsdk.ts +336 -0
  1133. package/src/engine/caserunner-sdk.ts +423 -0
  1134. package/src/engine/debugpi.ts +235 -0
  1135. package/src/eod.ts +669 -0
  1136. package/src/eodpinwatch.ts +556 -0
  1137. package/src/escalation.ts +1253 -0
  1138. package/src/eventloop.ts +1045 -0
  1139. package/src/execboundary.ts +633 -0
  1140. package/src/feedback.ts +1162 -0
  1141. package/src/findingscheck.ts +298 -0
  1142. package/src/fsdenied.ts +24 -0
  1143. package/src/ghread.ts +242 -0
  1144. package/src/github.ts +1497 -0
  1145. package/src/homes.ts +175 -0
  1146. package/src/hostroute.ts +53 -0
  1147. package/src/improvements.ts +787 -0
  1148. package/src/install.ts +1103 -0
  1149. package/src/installkind.ts +50 -0
  1150. package/src/ipc/capability.ts +333 -0
  1151. package/src/ipc/client.ts +269 -0
  1152. package/src/ipc/control.ts +90 -0
  1153. package/src/ipc/ghreadshim.ts +94 -0
  1154. package/src/ipc/launcher.ts +65 -0
  1155. package/src/ipc/permits.ts +362 -0
  1156. package/src/ipc/postshim.ts +164 -0
  1157. package/src/ipc/protocol.ts +342 -0
  1158. package/src/ipc/server.ts +371 -0
  1159. package/src/ipc/workerspec.ts +218 -0
  1160. package/src/learner/learner.ts +1655 -0
  1161. package/src/learner/miner.ts +1290 -0
  1162. package/src/learner/packet.ts +340 -0
  1163. package/src/learner/receipt.ts +168 -0
  1164. package/src/learner/status.ts +107 -0
  1165. package/src/ledgercheck.ts +157 -0
  1166. package/src/lessonledger.ts +703 -0
  1167. package/src/lessonselect.ts +888 -0
  1168. package/src/lessonshadow.ts +810 -0
  1169. package/src/levers.ts +393 -0
  1170. package/src/live/projection.ts +491 -0
  1171. package/src/live/publish.ts +92 -0
  1172. package/src/live/read.ts +86 -0
  1173. package/src/livecli.ts +336 -0
  1174. package/src/loginhint.ts +56 -0
  1175. package/src/loginrefresh/atomic.ts +76 -0
  1176. package/src/loginrefresh/lock.ts +104 -0
  1177. package/src/loginrefresh/main.ts +59 -0
  1178. package/src/loginrefresh/pirefresh.ts +57 -0
  1179. package/src/loginrefresh/refresher.ts +326 -0
  1180. package/src/loginrefresh/supervisor.ts +273 -0
  1181. package/src/loginrefresh/types.ts +35 -0
  1182. package/src/memory/context.ts +385 -0
  1183. package/src/memory/datafence.ts +9 -0
  1184. package/src/memory/delivery.ts +171 -0
  1185. package/src/memory/eventtags.ts +80 -0
  1186. package/src/memory/health.ts +953 -0
  1187. package/src/memory/import.ts +664 -0
  1188. package/src/memory/layout.ts +261 -0
  1189. package/src/memory/legacy-file.ts +104 -0
  1190. package/src/memory/lessons.ts +447 -0
  1191. package/src/memory/ovsession.ts +601 -0
  1192. package/src/memory/relayout.ts +335 -0
  1193. package/src/memory/roundactivity.ts +209 -0
  1194. package/src/memory/selection.ts +989 -0
  1195. package/src/memory/shadowstatus.ts +125 -0
  1196. package/src/memory/store.ts +275 -0
  1197. package/src/memory/textidentity.ts +8 -0
  1198. package/src/metrics.ts +1056 -0
  1199. package/src/missingconfig.ts +7 -0
  1200. package/src/npmverbs.ts +264 -0
  1201. package/src/onboard/choices.ts +222 -0
  1202. package/src/onboard/engine.ts +518 -0
  1203. package/src/onboard/launch.ts +115 -0
  1204. package/src/onboard/steps/appslug.ts +265 -0
  1205. package/src/onboard/steps/bringup.ts +482 -0
  1206. package/src/onboard/steps/compose.ts +459 -0
  1207. package/src/onboard/steps/configdelivery.ts +58 -0
  1208. package/src/onboard/steps/configfill.ts +1352 -0
  1209. package/src/onboard/steps/deploysh.ts +105 -0
  1210. package/src/onboard/steps/embeddings.ts +550 -0
  1211. package/src/onboard/steps/escalation.ts +640 -0
  1212. package/src/onboard/steps/githubapp.ts +1414 -0
  1213. package/src/onboard/steps/golive.ts +577 -0
  1214. package/src/onboard/steps/index.ts +71 -0
  1215. package/src/onboard/steps/ingress.ts +907 -0
  1216. package/src/onboard/steps/inventory.ts +526 -0
  1217. package/src/onboard/steps/llmauth.ts +1095 -0
  1218. package/src/onboard/steps/memory.ts +1290 -0
  1219. package/src/onboard/steps/memorykeys.ts +85 -0
  1220. package/src/onboard/steps/preflight.ts +191 -0
  1221. package/src/onboard/steps/proof.ts +624 -0
  1222. package/src/onboard/steps/ssh.ts +377 -0
  1223. package/src/onboard/steps/topology.ts +337 -0
  1224. package/src/onboard/steps/transport.ts +665 -0
  1225. package/src/onboard/steps/verifyup.ts +448 -0
  1226. package/src/onboard/steps/vmdeploy.ts +442 -0
  1227. package/src/onboard/toml.ts +50 -0
  1228. package/src/opencli.ts +591 -0
  1229. package/src/openpr.ts +568 -0
  1230. package/src/openviking/client.ts +1131 -0
  1231. package/src/openviking/context.ts +263 -0
  1232. package/src/openviking/embedder.ts +516 -0
  1233. package/src/openviking/gapsink.ts +63 -0
  1234. package/src/openviking/health.ts +83 -0
  1235. package/src/openviking/index.ts +119 -0
  1236. package/src/openviking/lessonfind.ts +92 -0
  1237. package/src/openviking/probe.ts +129 -0
  1238. package/src/openviking/proc.ts +110 -0
  1239. package/src/openviking/provisionreport.ts +160 -0
  1240. package/src/openviking/reembed.ts +412 -0
  1241. package/src/openviking/relayout.ts +177 -0
  1242. package/src/openviking/sidecar-main.ts +38 -0
  1243. package/src/openviking/sidecar.ts +106 -0
  1244. package/src/openviking/store.ts +2025 -0
  1245. package/src/openviking/supervisor.ts +474 -0
  1246. package/src/openviking/types.ts +174 -0
  1247. package/src/operator-recovery.ts +237 -0
  1248. package/src/operatormessage.ts +52 -0
  1249. package/src/outcomes.ts +1670 -0
  1250. package/src/piauthcopy.ts +12 -0
  1251. package/src/picli.ts +49 -0
  1252. package/src/picwd.ts +25 -0
  1253. package/src/pilogin.ts +37 -0
  1254. package/src/pingpong.ts +1339 -0
  1255. package/src/posting-journal.ts +549 -0
  1256. package/src/posting-outbox.ts +802 -0
  1257. package/src/posting-receipt.ts +324 -0
  1258. package/src/posting.ts +603 -0
  1259. package/src/postops.ts +832 -0
  1260. package/src/pr-activity.ts +20 -0
  1261. package/src/pr-author.ts +6 -0
  1262. package/src/pr-conversation.ts +432 -0
  1263. package/src/pr-session-lifecycle.ts +631 -0
  1264. package/src/preflight.ts +391 -0
  1265. package/src/priorresolve.ts +343 -0
  1266. package/src/qcrbin.ts +186 -0
  1267. package/src/recheck.ts +1775 -0
  1268. package/src/reconcile.ts +1030 -0
  1269. package/src/recordedfindings.ts +27 -0
  1270. package/src/regression.ts +833 -0
  1271. package/src/replay.ts +816 -0
  1272. package/src/requiredpasses.ts +148 -0
  1273. package/src/resumecheck.ts +246 -0
  1274. package/src/reviewcli.ts +787 -0
  1275. package/src/reviewcontext.ts +35 -0
  1276. package/src/reviewdetach.ts +734 -0
  1277. package/src/reviewhistory.ts +427 -0
  1278. package/src/reviewhome.ts +36 -0
  1279. package/src/reviewmemory.ts +133 -0
  1280. package/src/reviewrendercli.ts +139 -0
  1281. package/src/round-work.ts +42 -0
  1282. package/src/runhost.ts +108 -0
  1283. package/src/scanauth.ts +36 -0
  1284. package/src/scanbox.ts +1081 -0
  1285. package/src/scancli.ts +1296 -0
  1286. package/src/scandriverlog.ts +32 -0
  1287. package/src/session-bridge.ts +139 -0
  1288. package/src/session-command-payload.ts +35 -0
  1289. package/src/session-command-supervisor.ts +1142 -0
  1290. package/src/sessionjsonl.ts +88 -0
  1291. package/src/sessions.ts +659 -0
  1292. package/src/setup/adapters.ts +335 -0
  1293. package/src/setup/baselines.ts +110 -0
  1294. package/src/setup/caserunner.ts +611 -0
  1295. package/src/setup/configcommit.ts +443 -0
  1296. package/src/setup/engine.ts +1001 -0
  1297. package/src/setup/facts.ts +627 -0
  1298. package/src/setup/findings.ts +1264 -0
  1299. package/src/setup/history.ts +443 -0
  1300. package/src/setup/interview.ts +243 -0
  1301. package/src/setup/ledger.ts +324 -0
  1302. package/src/setup/pins.ts +66 -0
  1303. package/src/setup/portrait.ts +635 -0
  1304. package/src/setup/presentation.ts +18 -0
  1305. package/src/setup/profile.ts +508 -0
  1306. package/src/setup/replay.ts +370 -0
  1307. package/src/setup/replaybuild.ts +392 -0
  1308. package/src/setup/replayrun.ts +1096 -0
  1309. package/src/setup/replaysource.ts +198 -0
  1310. package/src/setup/retune.ts +415 -0
  1311. package/src/setup/retunelog.ts +95 -0
  1312. package/src/setup/scan.ts +1033 -0
  1313. package/src/setup/scanbuild.ts +168 -0
  1314. package/src/setup/scanfacts.ts +107 -0
  1315. package/src/setup/scanlease.ts +297 -0
  1316. package/src/setup/scanreport.ts +373 -0
  1317. package/src/setup/scanrun.ts +2268 -0
  1318. package/src/setup/scantree.ts +259 -0
  1319. package/src/setup/stage2.ts +926 -0
  1320. package/src/setup/stage2request.ts +347 -0
  1321. package/src/setup/survey.ts +458 -0
  1322. package/src/setup/surveyrun.ts +758 -0
  1323. package/src/setup/textsniff.ts +95 -0
  1324. package/src/setup/trackersink.ts +433 -0
  1325. package/src/setup/triage.ts +768 -0
  1326. package/src/setup/tuning.ts +766 -0
  1327. package/src/setup/unitcut.ts +523 -0
  1328. package/src/singleflight.ts +86 -0
  1329. package/src/slack/announce.ts +911 -0
  1330. package/src/slack/api.ts +303 -0
  1331. package/src/slack/messages.ts +288 -0
  1332. package/src/slack/origin.ts +599 -0
  1333. package/src/slack/policy.ts +354 -0
  1334. package/src/slack/reply.ts +201 -0
  1335. package/src/slack/router.ts +285 -0
  1336. package/src/slack/socket.ts +384 -0
  1337. package/src/slack/types.ts +108 -0
  1338. package/src/sqlitehint.ts +32 -0
  1339. package/src/ssh-observation.ts +30 -0
  1340. package/src/state.ts +8243 -0
  1341. package/src/statemachine.ts +369 -0
  1342. package/src/stubs.ts +68 -0
  1343. package/src/takeover.ts +634 -0
  1344. package/src/takeoverpi.ts +293 -0
  1345. package/src/terminal-failure.ts +41 -0
  1346. package/src/thread-resolution-refusal.ts +2 -0
  1347. package/src/tmux.ts +153 -0
  1348. package/src/trackerid.ts +41 -0
  1349. package/src/transcriptindex.ts +665 -0
  1350. package/src/tui/actions.ts +484 -0
  1351. package/src/tui/alerts.ts +666 -0
  1352. package/src/tui/app.ts +1979 -0
  1353. package/src/tui/archiveops.ts +192 -0
  1354. package/src/tui/autofile.ts +233 -0
  1355. package/src/tui/board.ts +1432 -0
  1356. package/src/tui/candidates.ts +889 -0
  1357. package/src/tui/cellwidth.ts +148 -0
  1358. package/src/tui/changelog-store.ts +503 -0
  1359. package/src/tui/chord.ts +25 -0
  1360. package/src/tui/clipboard.ts +92 -0
  1361. package/src/tui/cmdbar.ts +296 -0
  1362. package/src/tui/companion.ts +1427 -0
  1363. package/src/tui/companionplan.ts +247 -0
  1364. package/src/tui/companiontab.ts +83 -0
  1365. package/src/tui/confighome.ts +155 -0
  1366. package/src/tui/connect.ts +68 -0
  1367. package/src/tui/deploy-ceremony.ts +104 -0
  1368. package/src/tui/deploy-drain.ts +129 -0
  1369. package/src/tui/deploy-process.ts +265 -0
  1370. package/src/tui/deploytab.ts +1523 -0
  1371. package/src/tui/design.ts +125 -0
  1372. package/src/tui/digesttab.ts +214 -0
  1373. package/src/tui/emptystate.ts +39 -0
  1374. package/src/tui/evidence.ts +999 -0
  1375. package/src/tui/feed.ts +604 -0
  1376. package/src/tui/feedbacktab.ts +1077 -0
  1377. package/src/tui/filters.ts +90 -0
  1378. package/src/tui/ghread.ts +321 -0
  1379. package/src/tui/historypull.ts +81 -0
  1380. package/src/tui/inboxpull.ts +236 -0
  1381. package/src/tui/index.ts +1565 -0
  1382. package/src/tui/issuesink.ts +238 -0
  1383. package/src/tui/jsonfile.ts +42 -0
  1384. package/src/tui/keys.ts +109 -0
  1385. package/src/tui/layout.ts +108 -0
  1386. package/src/tui/learning.ts +627 -0
  1387. package/src/tui/lessonswitch.ts +118 -0
  1388. package/src/tui/livecontrol.ts +228 -0
  1389. package/src/tui/memforward.ts +443 -0
  1390. package/src/tui/memincident.ts +363 -0
  1391. package/src/tui/memory.ts +620 -0
  1392. package/src/tui/memtab.ts +606 -0
  1393. package/src/tui/metricstab.ts +1177 -0
  1394. package/src/tui/model.ts +131 -0
  1395. package/src/tui/mouse.ts +98 -0
  1396. package/src/tui/msg.ts +268 -0
  1397. package/src/tui/nativecompanion.ts +417 -0
  1398. package/src/tui/openurl.ts +21 -0
  1399. package/src/tui/paint.ts +511 -0
  1400. package/src/tui/panes.ts +98 -0
  1401. package/src/tui/pipane.ts +219 -0
  1402. package/src/tui/poll-hooks.ts +12 -0
  1403. package/src/tui/poll.ts +147 -0
  1404. package/src/tui/proposals.ts +838 -0
  1405. package/src/tui/prpause.ts +150 -0
  1406. package/src/tui/reload.ts +436 -0
  1407. package/src/tui/remote.ts +413 -0
  1408. package/src/tui/rollover.ts +969 -0
  1409. package/src/tui/scantab.ts +1290 -0
  1410. package/src/tui/setupentry.ts +93 -0
  1411. package/src/tui/sidebar.ts +749 -0
  1412. package/src/tui/sshtriage.ts +510 -0
  1413. package/src/tui/startup.ts +231 -0
  1414. package/src/tui/tabs.ts +45 -0
  1415. package/src/tui/termmirror.ts +224 -0
  1416. package/src/tui/theme.ts +95 -0
  1417. package/src/tui/ticketstab.ts +310 -0
  1418. package/src/tui/tmuxsocket.ts +129 -0
  1419. package/src/tui/trackertickets.ts +84 -0
  1420. package/src/tui/unwedge.ts +286 -0
  1421. package/src/tui/viewer.ts +575 -0
  1422. package/src/tui/viewerinput.ts +173 -0
  1423. package/src/updatenotice.ts +178 -0
  1424. package/src/usage.ts +1154 -0
  1425. package/src/verdicts.ts +4689 -0
  1426. package/src/version.ts +80 -0
  1427. package/src/wakes.ts +476 -0
  1428. package/src/webhook.ts +942 -0
  1429. package/src/webhookheal.ts +276 -0
  1430. package/src/wire.ts +2153 -0
  1431. package/src/worker-session-host.ts +602 -0
  1432. package/src/workerbreaker.ts +156 -0
  1433. package/src/workercontrol.ts +104 -0
  1434. package/src/workerlease.ts +441 -0
  1435. package/src/workerliveness.ts +103 -0
  1436. package/src/workerlog.ts +79 -0
  1437. package/src/workerruntime.ts +30 -0
  1438. package/src/workersupervisor.ts +1538 -0
  1439. package/src/workerusage.ts +42 -0
  1440. package/src/workerworld.ts +427 -0
  1441. package/src/worktrees.ts +1138 -0
  1442. package/tests/fixtures/regression-cases.json +795 -0
  1443. package/tests/fixtures/seed-manifest.json +19 -0
@@ -0,0 +1,1143 @@
1
+ // Board screen: semantic truecolor everywhere, rich PR rows (author, last-tick
2
+ // age, rounds, verdict chip), colored glyph legend, section titles with
3
+ // subtitles, clickable zones for full mouse navigation, OSC-8 PR links.
4
+ // Pure: (view, cols, rows) → Frame (+ zones/meta for the input layer).
5
+ import { archiveAttention, readArchiveStatus } from "../archive/status.js";
6
+ import { readDaemonLoad, stallShortPhrase } from "../eventloop.js";
7
+ import { curationNeedsAttention, earlierPhrase } from "../learner/status.js";
8
+ import { fmtDuration, isAuthResult, MEMORY_OFF_NO_DOCKER } from "../memory/health.js";
9
+ import { cancelCauseLabel, isLoudCancelCause } from "../state.js";
10
+ import { barHeight, paintCmdBar } from "./cmdbar.js";
11
+ import { filterLabel, visiblePrs } from "./filters.js";
12
+ import { glyphFor } from "./model.js";
13
+ import { windowStart } from "./panes.js";
14
+ import { ACCENT, ACCENT_BG, HEADING, MUTED, RESET as DRESET, STRONG, WARN, modeBadge, sectionTitle, selected as selectedLine, } from "./design.js";
15
+ import { Frame, charWidth, displayWidth, fit, rule, RULE_SEGMENT_SEP, sanitizeText, stripAnsi, truncate, wrap, } from "./paint.js";
16
+ import { paneSurface } from "./viewer.js";
17
+ import { viewerInputRow } from "./viewerinput.js";
18
+ import { lensForAgent, roundExecutionStage, } from "@quickchatai/pi-quickreview/src/round-progress.js";
19
+ import { FG, RESET, fmtAge, legendLine, osc8, prUrl, stateColor, verdictChip } from "./theme.js";
20
+ // ---- layout ----------------------------------------------------------------
21
+ /** "held by the operator" / "held by a session, lapses 12:30:00Z";
22
+ * an older daemon reports no holder, and that is said rather than guessed. */
23
+ export function leverHolderLabel(by, until) {
24
+ if (by === undefined)
25
+ return "holder unknown (older daemon)";
26
+ const who = by === "operator" ? "held by the operator" : "held by a session";
27
+ return until ? `${who}, lapses ${until.slice(11, 19)}Z` : `${who} until lifted`;
28
+ }
29
+ /** The drain bar's hold marker: ` · HOLD …` for the operator's no-auto-lift
30
+ * drain, ` · hold ?` for an operator drain from a daemon that reports no
31
+ * marker (honest unknown), nothing otherwise. */
32
+ export function drainHoldLabel(s) {
33
+ if (s.draining_hold === true)
34
+ return " · HOLD: no boot lifts it, drain off does";
35
+ if (s.draining_hold === undefined && s.draining_by === "operator")
36
+ return " · hold ?";
37
+ return "";
38
+ }
39
+ /** The pause chip on a PR row: `⏸op` for the operator's hold, `⏸` + the lapse time for a session's. */
40
+ function pauseChip(pr) {
41
+ if (!pr.paused)
42
+ return "";
43
+ if (!pr.pause)
44
+ return "⏸";
45
+ if (pr.pause.issuer === "operator")
46
+ return "⏸op";
47
+ return pr.pause.expires_at ? `⏸→${pr.pause.expires_at.slice(11, 16)}Z` : "⏸";
48
+ }
49
+ /** A PR row's verdict chip: a held review failure, else the last verdict. */
50
+ function rowChip(pr) {
51
+ if (pr.review_failure)
52
+ return `${FG.anomaly}FAILED_LOUD${RESET}`;
53
+ // The worker crash-loop breaker parked it: no worker starts until rerun-round / restart-session.
54
+ if (pr.worker_crash?.parked_at)
55
+ return `${FG.anomaly}PARKED${RESET}`;
56
+ return verdictChip(pr.last_verdict);
57
+ }
58
+ /** A PR title as one inert line — it is the author's text, and the row is
59
+ * written straight to the terminal. */
60
+ function rowTitle(pr) {
61
+ return oneLine(pr.title);
62
+ }
63
+ /** A PR row as `styledRow` paints it, without its styling — what the list
64
+ * is sized to. */
65
+ function rowPlain(pr, now) {
66
+ const rounds = pr.rounds ? `r${pr.rounds}` : "";
67
+ return [
68
+ glyphFor(pr),
69
+ `#${pr.number}`,
70
+ pr.author ?? "",
71
+ fmtAge(pr.updated_at, now),
72
+ rounds,
73
+ stripAnsi(rowChip(pr)),
74
+ pauseChip(pr),
75
+ rowTitle(pr),
76
+ ]
77
+ .filter((s) => s !== "")
78
+ .join(" ");
79
+ }
80
+ /** Left column sized to the longest PR row so titles aren't cropped while
81
+ * the detail pane sits empty — clamped to 45% of the terminal. */
82
+ export function listWidth(prs, cols, now = new Date(0)) {
83
+ const widest = prs.reduce((w, pr) => Math.max(w, displayWidth(rowPlain(pr, now))), displayWidth(stripAnsi(legendLine())));
84
+ return Math.min(Math.max(24, widest + 3), Math.floor(cols * 0.45));
85
+ }
86
+ /**
87
+ * What the board answers to on this frame (the bar is state-derived, so a
88
+ * button is painted exactly when its key would do something).
89
+ *
90
+ * The verbs that act on the selected PR appear only while there is one: with
91
+ * no snapshot, or an empty list, a `[u unwedge]` would be an action derived
92
+ * from no data — the second half of the honest-unknown rule. `g` also needs
93
+ * the repo slug the URL is built from. `e` toggles the events overlay
94
+ * regardless, and `I` (setup) is about the repo, not a PR. Inline: `a` is ⏎'s
95
+ * printable twin and `F` clears a filter the PRS subtitle is advertising.
96
+ */
97
+ export function boardKeys(view) {
98
+ const selected = visiblePrs(view)[view.selected] !== undefined;
99
+ const bar = [];
100
+ if (selected)
101
+ bar.push({ key: "\r", label: "⏎ pi pane" }, { key: "m", label: "m message" });
102
+ if (selected && view.repo)
103
+ bar.push({ key: "g", label: "g github" });
104
+ bar.push({ key: "e", label: "e events" });
105
+ if (selected)
106
+ bar.push({ key: "u", label: "u unwedge" });
107
+ // Setup is about the repo, not a PR — offered whatever is selected.
108
+ bar.push({ key: "I", label: "I setup" });
109
+ const inline = [];
110
+ if (selected)
111
+ inline.push("a");
112
+ if (view.boardFilter != null)
113
+ inline.push("F");
114
+ // A worker-hosted PR's pane is the transcript viewer: `[ ]` step its streams
115
+ // and `< >` its rounds. They are the pane header's keys (painted there), so
116
+ // they exist only while the selected PR's pane is the viewer.
117
+ const pr = visiblePrs(view)[view.selected];
118
+ if (pr !== undefined && paneSurface(pr.runtime, pr.number).kind === "viewer")
119
+ inline.push("[", "]", "<", ">");
120
+ return { bar, inline };
121
+ }
122
+ /** Rows the command bar takes on the board at this width — the one number
123
+ * `renderBoard` and the App's pi-viewport arithmetic must agree on. */
124
+ export function boardBarHeight(view, cols) {
125
+ return barHeight("board", cols, boardKeys(view).bar);
126
+ }
127
+ /**
128
+ * The live pi mirror owns the bottom half of the board. Two rows are chrome
129
+ * (divider + header), the rest is session tail.
130
+ * Floors at 6 rows and never squeezes the list/detail body below 3.
131
+ */
132
+ export function piRows(rows, barRows) {
133
+ const usable = rows - 2 - barRows; // top bar + command bar + bottom border
134
+ return Math.max(0, Math.min(Math.max(6, Math.floor(usable * 0.5)), usable - 3));
135
+ }
136
+ /**
137
+ * The exact terminal geometry the mirrored pi session should have — the
138
+ * rectangle `renderBoard` paints its capture into, and nothing more.
139
+ *
140
+ * One source of truth on purpose, shared with the paint below: if these numbers
141
+ * drift, pi lays itself out for a terminal of a different size than the one its
142
+ * output is rendered in, which is the bug this exists to stop. Two of the pane's
143
+ * rows are chrome (divider + header); of the width, two cells are the board's
144
+ * borders and one is the leading space each mirror row is painted with.
145
+ */
146
+ export function piPaneSize(cols, rows, barRows) {
147
+ const lines = piRows(rows, barRows) - 2;
148
+ const width = cols - 4;
149
+ if (lines <= 0 || width <= 0)
150
+ return undefined;
151
+ return { cols: width, rows: lines };
152
+ }
153
+ /** Geometry of the floating EVENTS overlay: a centered band over the board,
154
+ * bordered top and bottom, ~60% of the height, never under the bar. */
155
+ export function eventsOverlayBand(rows, barRows) {
156
+ const height = Math.max(5, Math.min(Math.floor(rows * 0.6), rows - 3 - barRows));
157
+ return { top: Math.max(1, Math.floor((rows - height) / 2)), height };
158
+ }
159
+ // ---- pieces ----------------------------------------------------------------
160
+ /** The companion's alert badge as it sits in the top bar: tier color, today's
161
+ * count, the latest title, and how many repeats folded into counters. */
162
+ export function alertSegment(badge, focused) {
163
+ const latest = badge.latest;
164
+ if (!latest)
165
+ return "";
166
+ const color = latest.tier === "alert" ? FG.anomaly : FG.accent;
167
+ const glyph = latest.tier === "alert" ? "▲" : "•";
168
+ const where = latest.pr !== null ? ` #${latest.pr}` : "";
169
+ const folds = badge.folds > 0 ? ` +${badge.folds}` : "";
170
+ const label = `${glyph} ${badge.count}${where} ${truncate(latest.title, 40)}${folds}${focused ? " ⏎ companion" : ""}`;
171
+ return focused ? selectedLine(`${color}${label}${RESET}`) : `${color}${label}${RESET}`;
172
+ }
173
+ /** Short top-bar label per triage class — the long form lives in the list. */
174
+ const CONNECTION_LABEL = {
175
+ ok: "ssh ok",
176
+ local: "local",
177
+ "no-agent-key": "no ssh key loaded",
178
+ "wedged-master": "ssh master wedged",
179
+ "host-unreachable": "host down",
180
+ unknown: "cause unknown",
181
+ };
182
+ /**
183
+ * What the board says where the PR list would be, when it has never had a
184
+ * snapshot.
185
+ *
186
+ * The count is `?`, never `0` (an empty count reads as "the data is gone" when
187
+ * the truth is "I could not ask"), the reason is named, and the remedy is a
188
+ * command the operator can paste into their own shell.
189
+ */
190
+ export function unknownSourceLines(conn, width) {
191
+ const lines = [
192
+ `${FG.anomaly}the daemon has not answered yet${RESET}`,
193
+ `${FG.dim}nothing below is a measurement — it is not known${RESET}`,
194
+ "",
195
+ ];
196
+ if (conn && conn.kind !== "ok" && conn.kind !== "local") {
197
+ for (const l of wrap(stripAnsi(conn.cause), width))
198
+ lines.push(`${FG.dim}${l}${RESET}`);
199
+ if (conn.remedy !== "") {
200
+ lines.push("");
201
+ lines.push(`${STRONG}run this:${RESET}`);
202
+ for (const l of wrap(conn.remedy, width))
203
+ lines.push(`${FG.accent} ${l}${RESET}`);
204
+ // The remedy is a shell command, and the operator is inside the alt
205
+ // screen looking at it. For the one class `s` can clear in place — a key
206
+ // that is simply not loaded — say so here rather than leaving it to the
207
+ // `?` key map: otherwise the honest answer reads as "quit the TUI first".
208
+ if (conn.kind === "no-agent-key") {
209
+ for (const l of wrap("…or press s to be prompted for the key passphrase here", width))
210
+ lines.push(`${FG.dim}${l}${RESET}`);
211
+ }
212
+ }
213
+ }
214
+ else if (!conn) {
215
+ lines.push(`${FG.dim}checking the connection…${RESET}`);
216
+ }
217
+ // Bring-up progress is not painted here: the companion column is on every
218
+ // frame and carries it (sidebar.ts `startup`).
219
+ lines.push("");
220
+ lines.push(`${FG.dim}s re-checks the connection · r refreshes${RESET}`);
221
+ return lines.map((l) => truncate(l, width));
222
+ }
223
+ /** The detail pane's twin of the above: never "no PR selected" (which implies
224
+ * there were PRs to select from) when the list itself is unknown. */
225
+ export function unknownDetailLines(conn, width) {
226
+ const lines = [
227
+ `${STRONG}no data${RESET}`,
228
+ `${FG.dim}the TUI has not been able to read status.json${RESET}`,
229
+ ];
230
+ if (conn?.detail) {
231
+ lines.push("");
232
+ for (const l of wrap(`ssh said: ${stripAnsi(conn.detail)}`, width))
233
+ lines.push(`${FG.dim}${l}${RESET}`);
234
+ }
235
+ return lines.map((l) => truncate(l, width));
236
+ }
237
+ /**
238
+ * The board's reviewer-memory banner, from status.json `memory` and nothing
239
+ * else — never from OpenViking, which is the thing that may be down. The
240
+ * memory tab [2] only shows what the TUI's own store can reach, so this is
241
+ * where the daemon's view of memory health reaches a person.
242
+ *
243
+ * `loud` — down / refusing a key / degraded: painted right after the
244
+ * daemon health, where truncation reaches it last;
245
+ * `quiet` — not measured yet, not reported by this daemon, not monitored:
246
+ * a short dim mark at the end of the bar — honest, never healthy,
247
+ * and the first thing a narrow terminal drops;
248
+ * nothing — healthy, or no snapshot at all (the whole board already says
249
+ * it does not know).
250
+ */
251
+ export function memorySegment(snapshot, now) {
252
+ if (!snapshot)
253
+ return undefined;
254
+ const m = snapshot.memory;
255
+ if (!m)
256
+ return { text: `${FG.dim}mem ?${RESET}`, loud: false };
257
+ if (!m.enabled)
258
+ return {
259
+ text: `${FG.dim}${m.disabled_reason === MEMORY_OFF_NO_DOCKER ? MEMORY_OFF_NO_DOCKER : "mem off"}${RESET}`,
260
+ loud: false,
261
+ };
262
+ const since = Date.parse(m.incident?.since ?? m.since);
263
+ const age = Number.isFinite(since) ? ` ${fmtDuration(now.getTime() - since)}` : "";
264
+ switch (m.state) {
265
+ case "healthy":
266
+ return undefined;
267
+ case "unknown":
268
+ return { text: `${FG.dim}mem ?${RESET}`, loud: false };
269
+ case "degraded":
270
+ return {
271
+ // Memory that answers but cannot search says so.
272
+ text: `${WARN}▲ MEMORY DEGRADED${age}${m.serving?.ok === false ? " · search not serving" : ""}${DRESET}`,
273
+ loud: true,
274
+ };
275
+ case "down":
276
+ return {
277
+ text: `${FG.anomaly}⛔ MEMORY DOWN${age} · ${m.down_cause === "not_serving" ? "search not serving" : "no authenticated answer"}${RESET}`,
278
+ loud: true,
279
+ };
280
+ case "auth_failed": {
281
+ const d = isAuthResult(m.credentials.daemon);
282
+ const sess = isAuthResult(m.credentials.sessions);
283
+ const which = d && sess ? "both keys" : d ? "daemon key" : sess ? "sessions' key" : "a key";
284
+ return {
285
+ text: `${FG.anomaly}⛔ MEMORY AUTH FAILED${age} · ${which} refused${RESET}`,
286
+ loud: true,
287
+ };
288
+ }
289
+ }
290
+ }
291
+ /**
292
+ * The board's EOD-curation banner, from status.json
293
+ * `memory.curation` alone: loud when the day's curation did not reach memory
294
+ * — no receipt (`missing`), or a lesson refused or not found
295
+ * (`not_persisted`). Both are also overseer wakes; this is the half a person
296
+ * sees, beside the memory banner. A block the daemon could not read (`null`)
297
+ * is a dim `curation ?` — honest-unknown: painting nothing would read the
298
+ * same as a quiet day, which `qcr status` and the companion's view both call
299
+ * unknown. Nothing for a daemon that reports no block (`undefined`: memory
300
+ * off, or an older daemon), and a quiet day is quiet.
301
+ */
302
+ export function curationSegment(snapshot) {
303
+ const c = snapshot?.memory?.curation;
304
+ if (c === null && snapshot?.memory)
305
+ return `${FG.dim}curation ?${RESET}`;
306
+ if (!curationNeedsAttention(c) || !c)
307
+ return undefined;
308
+ return c.state === "missing"
309
+ ? `${FG.anomaly}⛔ EOD CURATION MISSING ${c.day ?? "?"} · ${c.offered} candidate${c.offered === 1 ? "" : "s"}, no receipt${earlierPhrase(c)}${RESET}`
310
+ : `${FG.anomaly}⛔ LESSONS NOT PERSISTED ${c.day ?? "?"} · ${c.not_persisted}${earlierPhrase(c)}${RESET}`;
311
+ }
312
+ /**
313
+ * The board's archive banner (docs/archiving.md §11), from
314
+ * status.json `archive` alone, through its total reader: loud only for what
315
+ * needs a person (`archiveAttention`) — held for disk, a restore that failed,
316
+ * a reopened PR no tick or birth will restore (mode not `on`: its archived
317
+ * receipts read unknown until `qcr archive restore`), or repeated verify
318
+ * failures. A block this build cannot read is a dim `archive ?`, never
319
+ * silence; nothing for a daemon that reports no block, and a quiet archiver
320
+ * is quiet.
321
+ */
322
+ export function archiveSegment(snapshot) {
323
+ if (!snapshot)
324
+ return undefined;
325
+ const r = readArchiveStatus(snapshot.archive);
326
+ if (r.kind === "absent")
327
+ return undefined;
328
+ if (r.kind === "unreadable")
329
+ return `${FG.dim}archive ?${RESET}`;
330
+ const parts = archiveAttention(r.view);
331
+ return parts.length > 0 ? `${FG.anomaly}⛔ ARCHIVE ${parts.join(" · ")}${RESET}` : undefined;
332
+ }
333
+ /**
334
+ * The board's event-loop banner, from status.json `daemon` and nothing else:
335
+ * the daemon measuring its own loop, so a stalled loop (an unanswered /health)
336
+ * is visible on the board.
337
+ *
338
+ * `loud` — stalled: painted beside the memory banner, with the cause the
339
+ * evidence names (the loop itself blocked / CPU starved /
340
+ * cause unknown);
341
+ * `quiet` — not measured yet, not reported by this daemon (an older one),
342
+ * or a block this build cannot read whole (a newer daemon's state,
343
+ * a missing field): a short dim `loop ?` at the end of the bar —
344
+ * honest, never ok;
345
+ * nothing — ok, or no snapshot at all.
346
+ *
347
+ * The block is parsed JSON, read through `readDaemonLoad`: nothing in it can
348
+ * throw out of a paint.
349
+ */
350
+ export function eventLoopSegment(snapshot) {
351
+ if (!snapshot)
352
+ return undefined;
353
+ const r = readDaemonLoad(snapshot.daemon);
354
+ if (r.kind !== "read" || r.view.event_loop.state === "unknown")
355
+ return { text: `${FG.dim}loop ?${RESET}`, loud: false };
356
+ if (r.view.event_loop.state === "ok")
357
+ return undefined;
358
+ return { text: `${FG.anomaly}⛔ ${stallShortPhrase(snapshot.daemon)}${RESET}`, loud: true };
359
+ }
360
+ /** Top-bar segments, left to right — shared by the renderer and the hit-test
361
+ * geometry so the alert click zone can never drift from the text. */
362
+ function barSegments(view, alerts) {
363
+ const mode = modeBadge(view.dryRun);
364
+ let health;
365
+ switch (view.health.kind) {
366
+ case "ok":
367
+ health = `${FG.approve}●${RESET} daemon ok (hb ${view.health.heartbeatAgeS}s)`;
368
+ break;
369
+ case "pipeline_unhealthy":
370
+ health = `${FG.anomaly}⛔ daemon alive · PIPELINE FAILED · ${view.health.causes.length} (hb ${view.health.heartbeatAgeS}s)${RESET}`;
371
+ break;
372
+ case "stale":
373
+ health = `${WARN}▲ DATA STALE (${view.health.dataAgeS}s)${DRESET}`;
374
+ break;
375
+ case "unreachable":
376
+ health = `${FG.anomaly}✖ unreachable${view.connection ? ` · ${CONNECTION_LABEL[view.connection.kind]}` : ""}${RESET}`;
377
+ break;
378
+ }
379
+ const s = view.snapshot;
380
+ const rounds = s ? `rounds ${s.running_rounds}/${s.max_concurrent_rounds ?? "?"}` : "";
381
+ const spend = s?.today_spend_usd !== undefined ? `today $${s.today_spend_usd.toFixed(2)}` : "";
382
+ // Deploy-window drain: while the daemon drains, the bar says so loudly,
383
+ // with how many rounds still have to finish before a deploy is safe and how
384
+ // many webhook deliveries were dropped so far — and by whom, and when it
385
+ // lapses: an operator's drain holds until lifted, a session's always has an
386
+ // expiry. An older daemon that reports neither is shown as such rather than
387
+ // guessed at. The operator's HOLD says that no boot lifts it; an
388
+ // operator drain from a daemon that reports no hold marker says "hold ?".
389
+ const drainSeg = s?.draining
390
+ ? `${FG.anomaly}⛔ DRAINING — ${s.running_rounds} round${s.running_rounds === 1 ? "" : "s"} finishing · ${s.drain_failed_loud ?? 0} failed loud · ${s.drained_deliveries ?? 0} dropped · ${leverHolderLabel(s.draining_by, s.draining_until)}${drainHoldLabel(s)}${s.draining_reason === "worker_failures" ? " · workers keep failing, drain off lifts it" : ""}${RESET}`
391
+ : "";
392
+ const td = s?.thread_decisions;
393
+ const breakerSeg = td && (td.breaker_state !== "closed" || td.failed > 0)
394
+ ? `${FG.anomaly}⛔ THREAD RETRY ${td.breaker_state.toUpperCase()}${td.open_until ? ` until ${td.open_until.slice(11, 19)}Z` : ""} · ${td.pending} pending · ${td.failed} failed${RESET}`
395
+ : "";
396
+ const badge = alerts && view.alerts ? alertSegment(view.alerts, view.alertFocus === true) : "";
397
+ const mem = memorySegment(s, view.now ?? new Date());
398
+ const curation = curationSegment(s) ?? "";
399
+ const archive = archiveSegment(s) ?? "";
400
+ const loop = eventLoopSegment(s);
401
+ return [
402
+ `${HEADING}quickreview${DRESET}`,
403
+ mode,
404
+ health,
405
+ mem?.loud ? mem.text : "",
406
+ loop?.loud ? loop.text : "",
407
+ curation,
408
+ archive,
409
+ drainSeg,
410
+ breakerSeg,
411
+ rounds,
412
+ spend,
413
+ badge,
414
+ // Only when `alerts` — the hit-test geometry measures the segments BEFORE
415
+ // the badge, and a quiet mark sits after it.
416
+ alerts && mem && !mem.loud ? mem.text : "",
417
+ alerts && loop && !loop.loud ? loop.text : "",
418
+ ].filter((x) => x !== "");
419
+ }
420
+ export function topBar(view, cols) {
421
+ return rule(cols, "┌", "┐", barSegments(view, true));
422
+ }
423
+ /**
424
+ * 1-based screen columns of the alert badge inside the top bar, or undefined
425
+ * when there is no badge. Derived from the same segment list `topBar` renders:
426
+ * `rule` lays out `border + " " + segments.join(" ── ") + " "`, so the badge
427
+ * starts one column past the border, the leading space, and every earlier
428
+ * segment.
429
+ */
430
+ export function alertZone(view, cols) {
431
+ if (!view.alerts?.latest)
432
+ return undefined;
433
+ const before = barSegments(view, false);
434
+ const prefix = before.length > 0 ? `${before.join(RULE_SEGMENT_SEP)}${RULE_SEGMENT_SEP}` : "";
435
+ const x1 = 3 + displayWidth(stripAnsi(prefix));
436
+ const width = displayWidth(stripAnsi(alertSegment(view.alerts, view.alertFocus === true)));
437
+ if (x1 >= cols)
438
+ return undefined; // truncated away on a narrow terminal
439
+ return { x1, x2: Math.min(cols - 1, x1 + width - 1) };
440
+ }
441
+ function styledRow(pr, selected, width, now, repo) {
442
+ const color = stateColor(pr.stale_recheck ? "reviewing" : pr.state);
443
+ const chip = rowChip(pr);
444
+ const rounds = pr.rounds ? `${FG.dim}r${pr.rounds}${RESET}` : "";
445
+ const paused = pr.paused ? `${WARN}${pauseChip(pr)}${DRESET}` : "";
446
+ const head = `${color}${glyphFor(pr)} ${STRONG}#${pr.number}${RESET}`;
447
+ const meta = [
448
+ `${FG.author}${pr.author ?? ""}${RESET}`,
449
+ `${FG.dim}${fmtAge(pr.updated_at, now)}${RESET}`,
450
+ rounds,
451
+ chip,
452
+ paused,
453
+ ]
454
+ .filter((s) => stripAnsi(s) !== "")
455
+ .join(" ");
456
+ const used = displayWidth(`${stripAnsi(head)} ${stripAnsi(meta)} `);
457
+ const title = truncate(rowTitle(pr), Math.max(4, width - used - 1));
458
+ const numLinked = repo
459
+ ? `${color}${glyphFor(pr)} ${STRONG}${osc8(prUrl(repo, pr.number), `#${pr.number}`)}${RESET}`
460
+ : head;
461
+ const body = `${numLinked} ${meta} ${title}`;
462
+ const pad = " ".repeat(Math.max(0, width - displayWidth(body) - 1));
463
+ return selected ? selectedLine(` ${body}${pad}`) : ` ${body}${pad}`;
464
+ }
465
+ const VERDICT_ABBREV = {
466
+ REQUEST_CHANGES: "RC",
467
+ APPROVE: "APPROVE",
468
+ COMMENT: "COMMENT",
469
+ };
470
+ function section(title, subtitle) {
471
+ return sectionTitle(title, subtitle);
472
+ }
473
+ function durationLabel(ms) {
474
+ const seconds = Math.max(0, Math.floor(ms / 1_000));
475
+ if (seconds < 60)
476
+ return `${seconds}s`;
477
+ const minutes = Math.floor(seconds / 60);
478
+ if (minutes < 60)
479
+ return `${minutes}m`;
480
+ const hours = Math.floor(minutes / 60);
481
+ return `${hours}h${minutes % 60 > 0 ? ` ${minutes % 60}m` : ""}`;
482
+ }
483
+ function oneLine(value) {
484
+ return sanitizeText(value).replace(/\s+/g, " ").trim();
485
+ }
486
+ function currentProgressLines(round, progress, width, now, rowsOut, firstLine = 0) {
487
+ const lines = [];
488
+ const started = Date.parse(round.started_at);
489
+ const deadline = round.deadline_at ? Date.parse(round.deadline_at) : Number.NaN;
490
+ const nowMs = now.getTime();
491
+ const elapsed = Number.isFinite(started) ? durationLabel(nowMs - started) : "?";
492
+ const deadlineText = Number.isFinite(deadline)
493
+ ? deadline >= nowMs
494
+ ? `${durationLabel(deadline - nowMs)} left`
495
+ : `${durationLabel(nowMs - deadline)} OVERDUE`
496
+ : "deadline unavailable";
497
+ lines.push(truncate(section("CURRENT REVIEW", `round ${round.round_no} · ${elapsed} elapsed · ${deadlineText}`), width));
498
+ // A sticky session may process neighboring wakes at nearly identical times.
499
+ // Only the exact durable delivery + prompt-derived round/head identity may
500
+ // paint this round; timestamp proximity is not identity.
501
+ const current = progress?.version === 2 &&
502
+ round.command_id !== undefined &&
503
+ progress.command_id === round.command_id &&
504
+ round.command_sha256 !== undefined &&
505
+ progress.command_sha256 === round.command_sha256 &&
506
+ round.head_sha !== undefined &&
507
+ progress.head_sha === round.head_sha &&
508
+ progress.round_no === round.round_no
509
+ ? progress
510
+ : undefined;
511
+ const planned = round.lenses
512
+ .split(",")
513
+ .map((x) => x.trim())
514
+ .filter(Boolean);
515
+ // The validator runs at its own tier, shown beside its row.
516
+ const tierOf = (name) => name === "pass-validate" && round.validate_tier ? ` · ${round.validate_tier}` : "";
517
+ if (!current) {
518
+ lines.push(truncate(` ${FG.dim}? parent · live progress unavailable${RESET}`, width));
519
+ for (const name of planned) {
520
+ lines.push(truncate(` ${FG.dim}? ${name} · unknown${tierOf(name)}${RESET}`, width));
521
+ }
522
+ lines.push(truncate(` ${FG.dim}? final verdict · unknown${RESET}`, width));
523
+ return lines;
524
+ }
525
+ const signalAge = Math.max(0, nowMs - Date.parse(current.updated_at));
526
+ const signal = signalAge >= 60_000
527
+ ? `SILENT ${durationLabel(signalAge)}`
528
+ : `signal ${durationLabel(signalAge)} ago`;
529
+ const parentColor = signalAge >= 120_000 ? FG.anomaly : current.parent_status === "active" ? FG.accent : FG.dim;
530
+ const active = current.active_tool ? ` · ${oneLine(current.active_tool)}` : "";
531
+ const stage = roundExecutionStage(current, planned);
532
+ const stageDeadline = stage === "accepted" || stage === "preparing"
533
+ ? round.stage_deadlines?.first_pass_start
534
+ : stage === "fanout-started"
535
+ ? round.stage_deadlines?.passes_complete
536
+ : undefined;
537
+ const due = stageDeadline
538
+ ? ` · stage ${Date.parse(stageDeadline) >= nowMs ? `due in ${durationLabel(Date.parse(stageDeadline) - nowMs)}` : `OVERDUE ${durationLabel(nowMs - Date.parse(stageDeadline))}`}`
539
+ : "";
540
+ lines.push(truncate(` ${parentColor}parent ${current.parent_status.toUpperCase()} · ${stage}${due} · ${signal}${active}${RESET}`, width));
541
+ const agentLine = (name, agent) => {
542
+ const tier = tierOf(name);
543
+ if (!agent)
544
+ return ` ${FG.dim}○ ${name} · pending${tier}${RESET}`;
545
+ if (agent.status === "running") {
546
+ const tool = agent.current_tool ? ` · ${oneLine(agent.current_tool)}` : "";
547
+ return ` ${FG.accent}⟳ ${name} · running ${durationLabel(agent.duration_ms)}${tool}${tier}${RESET}`;
548
+ }
549
+ if (agent.status === "failed") {
550
+ const error = agent.error ? ` · ${oneLine(agent.error)}` : "";
551
+ return ` ${FG.anomaly}✗ ${name} · failed after ${durationLabel(agent.duration_ms)}${error}${tier}${RESET}`;
552
+ }
553
+ return ` ${FG.approve}✓ ${name} · done in ${durationLabel(agent.duration_ms)} · ${agent.tool_count} tools${tier}${RESET}`;
554
+ };
555
+ // Every execution of a planned lens is shown — a lens run twice (two task
556
+ // rows) never hides a running or failed sibling behind a finished one.
557
+ const runs = new Map();
558
+ for (const agent of current.agents) {
559
+ const name = lensForAgent(agent.agent);
560
+ runs.set(name, [...(runs.get(name) ?? []), agent]);
561
+ }
562
+ for (const name of new Set(planned)) {
563
+ const executions = runs.get(name) ?? [];
564
+ const rows = Math.max(planned.filter((p) => p === name).length, executions.length);
565
+ for (let i = 0; i < rows; i++) {
566
+ rowsOut?.push({ line: firstLine + lines.length, lens: name, nth: i });
567
+ lines.push(truncate(agentLine(name, executions[i]), width));
568
+ }
569
+ }
570
+ // The parent may justify and add a lens outside the dispatch plan. Those
571
+ // agents are real work too; omitting them would make "all agents" false.
572
+ const added = new Map();
573
+ for (const agent of current.agents.filter((item) => !planned.includes(lensForAgent(item.agent)))) {
574
+ const lens = lensForAgent(agent.agent);
575
+ const nth = added.get(lens) ?? 0;
576
+ added.set(lens, nth + 1);
577
+ rowsOut?.push({ line: firstLine + lines.length, lens, nth });
578
+ const rendered = agentLine(agent.agent, agent).replace(`${RESET}`, ` · added${RESET}`);
579
+ lines.push(truncate(rendered, width));
580
+ }
581
+ lines.push(truncate(` ${FG.dim}○ final verdict · pending${RESET}`, width));
582
+ const activityAge = Math.max(0, nowMs - Date.parse(current.last_activity_at));
583
+ lines.push(truncate(` ${FG.dim}last activity ${durationLabel(activityAge)} ago · ${oneLine(current.last_activity)}${RESET}`, width));
584
+ if (signalAge >= 120_000) {
585
+ lines.push(truncate(` ${FG.anomaly}⚠ no live signal for ${durationLabel(signalAge)} — inspect raw PI below${RESET}`, width));
586
+ }
587
+ return lines;
588
+ }
589
+ /** Doubted findings shown before the "… N more" line. */
590
+ const DOUBTED_SHOWN = 8;
591
+ /**
592
+ * The DOUBTED section: findings the validator could not stand behind
593
+ * — kept in the findings record as "may not be valid", never posted on the PR,
594
+ * and put here for the operator to judge. Newest round first. Nothing renders
595
+ * when there are none, or when an older daemon did not report the field.
596
+ */
597
+ export function doubtedLines(doubted, width, title = "DOUBTED", note = "may not be valid · kept, never posted") {
598
+ if (!doubted || doubted.length === 0)
599
+ return [];
600
+ const lines = [truncate(section(title, note), width)];
601
+ const newest = [...doubted].sort((a, b) => b.round_no - a.round_no);
602
+ for (const f of newest.slice(0, DOUBTED_SHOWN)) {
603
+ const at = f.path ? ` ${sanitizeText(f.path)}${f.line !== null ? `:${f.line}` : ""}` : "";
604
+ const sev = f.severity ? ` · ${sanitizeText(f.severity)}` : "";
605
+ const word = f.word ? ` · ${sanitizeText(f.word)}` : "";
606
+ const why = f.reason ? ` — ${oneLine(f.reason)}` : "";
607
+ lines.push(truncate(` ${WARN}? r${f.round_no} ${sanitizeText(f.lens)}${at}${sev}${word}${DRESET}${FG.dim}${why}${RESET}`, width));
608
+ }
609
+ if (newest.length > DOUBTED_SHOWN)
610
+ lines.push(`${FG.dim} … ${newest.length - DOUBTED_SHOWN} more (qcr why <pr> --json)${RESET}`);
611
+ return lines;
612
+ }
613
+ export function detailLines(detail, pr, width, now = new Date(0), progress, progressRows) {
614
+ const lines = [];
615
+ if (!pr)
616
+ return ["no PR selected"];
617
+ lines.push(`${stateColor(pr.state)}${STRONG}#${pr.number}${RESET} ${STRONG}${truncate(sanitizeText(pr.title), width - 8 - String(pr.number).length)}${RESET}`);
618
+ const delivery = pr.current_round?.posting_delivery;
619
+ if (delivery) {
620
+ lines.push(truncate(`${FG.dim}POSTING PENDING · automatic retry · attempts ${delivery.attempts}${RESET}`, width));
621
+ lines.push(truncate(`next ${sanitizeText(delivery.next_attempt_at)}${delivery.last_error ? ` · ${oneLine(delivery.last_error)}` : ""}`, width));
622
+ }
623
+ if (!detail || detail.pr !== pr.number) {
624
+ lines.push(`${FG.dim}loading detail…${RESET}`);
625
+ return lines;
626
+ }
627
+ const round = pr.current_round?.round_no ??
628
+ (detail.rounds.length > 0 ? detail.rounds[detail.rounds.length - 1]?.round_no : undefined);
629
+ const facts = [
630
+ `${stateColor(detail.state ?? pr.state)}${detail.state ?? pr.state}${RESET}`,
631
+ ];
632
+ if (round !== undefined)
633
+ facts.push(`round ${round}`);
634
+ if (detail.author)
635
+ facts.push(`by ${FG.author}${detail.author}${RESET}`);
636
+ lines.push(truncate(facts.join(" · "), width));
637
+ const trig = detail.trigger_ts ? `trig ${fmtAge(detail.trigger_ts, now)} ago` : "trig —";
638
+ lines.push(truncate(`spend $${detail.spend_usd.toFixed(2)} · head ${(detail.head_sha ?? "").slice(0, 7)} · ${trig}`, width));
639
+ if (detail.labels && detail.labels.length > 0) {
640
+ lines.push(truncate(detail.labels.map((l) => `${FG.accent}[${sanitizeText(l)}]${RESET}`).join(" "), width));
641
+ }
642
+ if (pr.paused) {
643
+ // A held PR says who holds it and when the hold lapses.
644
+ const hold = pr.pause;
645
+ const why = hold?.reason ? ` · ${oneLine(sanitizeText(hold.reason))}` : "";
646
+ lines.push(truncate(`${WARN}${STRONG}PAUSED${DRESET}${WARN} · ${leverHolderLabel(hold?.issuer, hold?.expires_at ?? undefined)}${why}${DRESET}`, width));
647
+ }
648
+ if (pr.review_failure) {
649
+ const command = pr.review_failure.command_id ? ` · ${pr.review_failure.command_id}` : "";
650
+ const round = pr.review_failure.round_no !== null ? ` · round ${pr.review_failure.round_no}` : "";
651
+ lines.push(truncate(`${FG.anomaly}${STRONG}FAILED_LOUD${RESET}${FG.anomaly} · ${pr.review_failure.stage}${command}${round} · attempt ${pr.review_failure.attempts}/${pr.review_failure.retry_cap} · ${fmtAge(pr.review_failure.failed_at, now)} old${RESET}`, width));
652
+ const retry = pr.review_failure.next_action === "retry_wait" && pr.review_failure.next_retry_at
653
+ ? `auto retry ${pr.review_failure.next_retry_at.slice(11, 16)}Z · epoch ${pr.review_failure.retry_epoch} · u now`
654
+ : "press u to recover";
655
+ lines.push(truncate(`${FG.anomaly}${oneLine(pr.review_failure.detail)} · ${retry}${RESET}`, width));
656
+ }
657
+ lines.push(`${FG.dim}${"─".repeat(Math.max(0, width))}${RESET}`);
658
+ // status.json advances every poll and therefore owns current timing/plan;
659
+ // `why` is enriched and deliberately cached, so it is only the fallback for
660
+ // an older daemon that has not shipped current_round yet — and only while
661
+ // the snapshot says a round is under way: a cached `running` row outlives
662
+ // the round it describes until the next read lands.
663
+ const runningRound = pr.current_round ??
664
+ (pr.state === "reviewing"
665
+ ? [...detail.rounds].reverse().find((r) => r.status === "running")
666
+ : undefined);
667
+ if (runningRound)
668
+ lines.push(...currentProgressLines(runningRound, progress, width, now, progressRows, lines.length));
669
+ const lastSummary = [...detail.rounds]
670
+ .reverse()
671
+ .find((r) => r.summary && r.summary.trim().length > 0)?.summary;
672
+ if (lastSummary) {
673
+ lines.push(truncate(section("NOW", "the session's own 3-4 sentence read"), width));
674
+ for (const l of wrap(sanitizeText(lastSummary).trim(), width))
675
+ lines.push(l);
676
+ }
677
+ if (detail.description !== undefined) {
678
+ lines.push(truncate(section("DESCRIPTION", "the PR body"), width));
679
+ const raw = sanitizeText(detail.description).trim();
680
+ const desc = raw.length > 0 ? wrap(raw, width) : ["(empty)"];
681
+ for (const l of desc.slice(0, 12))
682
+ lines.push(l);
683
+ if (desc.length > 12)
684
+ lines.push(`${FG.dim}… ${desc.length - 12} more lines (open on GitHub with g)${RESET}`);
685
+ }
686
+ lines.push(truncate(section("LEDGER", "findings the conversation tracks"), width));
687
+ if (detail.ledger) {
688
+ for (const l of sanitizeText(detail.ledger).split("\n")) {
689
+ const t = l.trim();
690
+ if (t.length > 0)
691
+ for (const wl of wrap(t, width))
692
+ lines.push(wl);
693
+ }
694
+ }
695
+ else {
696
+ lines.push(truncate(`${FG.dim}none yet — the live ledger is pinned in the session${RESET}`, width));
697
+ }
698
+ // A cancelled round carries its own glyph, distinct from any other
699
+ // verdictless round, and the one loud cause — a round that stopped dead
700
+ // inside its deadline — is the only one that gets a color; a redeploy orphan
701
+ // stays dim on purpose.
702
+ const roundsBits = detail.rounds.map((r) => {
703
+ const cancelled = r.status === "cancelled";
704
+ const loud = cancelled && isLoudCancelCause(r.cancel_cause);
705
+ const v = r.verdict
706
+ ? (VERDICT_ABBREV[r.verdict] ?? r.verdict)
707
+ : cancelled
708
+ ? "✕"
709
+ : r.status === "running"
710
+ ? "…"
711
+ : "—";
712
+ const color = loud
713
+ ? FG.anomaly
714
+ : r.verdict === "APPROVE"
715
+ ? FG.approve
716
+ : r.verdict === "REQUEST_CHANGES"
717
+ ? FG.request_changes
718
+ : FG.dim;
719
+ return `r${r.round_no} ${color}${v}${RESET}`;
720
+ });
721
+ lines.push(truncate(`${section("ROUNDS", "review rounds + verdicts")} ${roundsBits.join(" · ") || "—"}`, width));
722
+ for (const r of detail.rounds) {
723
+ if (r.status !== "cancelled")
724
+ continue;
725
+ const loud = isLoudCancelCause(r.cancel_cause);
726
+ lines.push(truncate(` ${loud ? FG.anomaly : FG.dim}✕ r${r.round_no} cancelled — ${cancelCauseLabel(r.cancel_cause)}${RESET}`, width));
727
+ }
728
+ lines.push(...doubtedLines(detail.doubted, width));
729
+ // The profile's `[posting]` policy: survivors kept off the PR, same grammar.
730
+ lines.push(...doubtedLines(detail.withheld, width, "WITHHELD", "over the posting policy · kept, never posted"));
731
+ lines.push(truncate(`${section("THREADS", "bot review threads")} ${detail.threads.total} known`, width));
732
+ if (detail.comments && detail.comments.length > 0) {
733
+ lines.push(truncate(section("COMMENTS", "latest PR conversation"), width));
734
+ for (const c of detail.comments) {
735
+ lines.push(truncate(`${FG.author}${c.author}${RESET} ${FG.dim}${fmtAge(c.created_at, now)} ago${RESET}`, width));
736
+ const body = sanitizeText(c.body)
737
+ .split("\n")
738
+ .map((t) => t.trim())
739
+ .filter((t) => t.length > 0)
740
+ .join(" ");
741
+ const bodyLines = wrap(body, Math.max(8, width - 2));
742
+ for (const bl of bodyLines.slice(0, 2))
743
+ lines.push(` ${bl}`);
744
+ if (bodyLines.length > 2)
745
+ lines.push(` ${FG.dim}…${RESET}`);
746
+ }
747
+ }
748
+ return lines;
749
+ }
750
+ /**
751
+ * The `?` overlay. Pinned against docs/tui.md (tests/tui-surfaces.test.ts):
752
+ * every key named here is in some surface's vocabulary, and every surface
753
+ * the doc lists is named here. The bar shows what the current frame answers
754
+ * to; this is the whole map.
755
+ */
756
+ export const HELP_LINES = [
757
+ "1…8 the eight surfaces: board · memory · digest · tickets · deploy · metrics · feedback · scan",
758
+ " the bar at the foot shows what THIS frame answers to; a button that is not there is a key that would do nothing",
759
+ "r / s / ? / q refresh · reconnect VM ssh (the one ssh key-passphrase prompt) · this overlay · quit (asks first)",
760
+ "Ctrl-c ×3 kill the TUI from anywhere (terminal restored) — the un-stuck hatch",
761
+ " an alert in the top bar: click it or ⏎ to open the companion",
762
+ "the companion column down the right edge is on every tab:",
763
+ " type any key no tab claims (or /) — it is a terminal, every byte reaches pi; Ctrl-q releases",
764
+ " wheel over the column (or PgUp/PgDn while focused) walks its scrollback · drag its left edge to resize",
765
+ " the column is always there at full width — nothing in the TUI collapses it or goes full-screen",
766
+ "[1] board — the verbs act on the SELECTED PR, so they exist only while one is selected, and only here:",
767
+ "j/k ↓/↑ select PR (mouse: click a row; click again to focus its pi pane)",
768
+ "⏎ / a focus the selected PR's pi pane (embedded, below the list; Ctrl-q back) — it is a live terminal, not a picture",
769
+ "g open the PR on GitHub (PR numbers are Ctrl+clickable links)",
770
+ "[ / ] a worker-hosted PR's pane is a transcript viewer, not a terminal: previous / next stream (main, then each lens); a click on a progress row picks its lens",
771
+ "< / > past / later round in the viewer; PgUp / wheel parks it, End follows the tail again",
772
+ " its input line (focused pane): ⏎ steers the running round, or sends a message to an idle PR; Alt-⏎ queues a follow-up",
773
+ " Alt-p marks the next message may-post (shown, reset after send); Ctrl-c asks to abort the round (y confirms); [ ] < > are keys only while the line is empty",
774
+ "m quick-message the selected PR's session",
775
+ "u unwedge: cancel the running round and re-queue it (nothing posted, no GitHub write)",
776
+ "e events overlay (j/k scroll, e/Esc close; click an event → its PR)",
777
+ "F clear the board filter the PRS title is advertising",
778
+ "I set up the repo: the companion runs its setup skill (survey, interview, the repo profile)",
779
+ "[2] memory — the store, newest first, grouped by day:",
780
+ "j/k · [ / ] select an entry · jump to the older / newer day",
781
+ "e / p / x / n edit · pin or unpin · retire (x twice) · new #manual entry — painted beside the selected entry",
782
+ "W / F open OpenViking Studio through the memory forward · clear the tag filter",
783
+ "[3] digest — the EOD sweep's document: j/k scroll · [ / ] older / newer day",
784
+ "[4] tickets — what adjudication filed on the tracker: j/k choose · [ / ] scroll the body · c actionable ⇄ all",
785
+ "[5] deploy — V picks the version · D D deploys it (or click ▶ DEPLOY TO VM) · S S powers the VM app · x aborts a run / closes its log",
786
+ "[6] metrics — w / m / a switch the 7d / 30d / all window · # <pr> ⏎ opens a PR timeline (Esc back)",
787
+ "[7] feedback — the loop on one surface: signal → adjudication → proposal → change → revert",
788
+ "t focus the next pane: inbox → proposed → changed",
789
+ "a show / hide archived (acted-on) signals",
790
+ "A / x accept / reject the focused rubric proposal (accept applies + auto-ratifies + commits locally)",
791
+ "R then y arm and confirm a revert of the focused change — a local commit only, never pushed",
792
+ "[8] scan — the whole-repo scan: units left, the unit's findings by validity tier (confirmed first; style grouped per rule) over the detail, the run on top:",
793
+ "[ / ] · j/k previous / next unit · select a finding",
794
+ "p / d promote (the companion files one ticket each; unconfirmed ones need an explicit yes) · dismiss with a reason (it becomes reviewer memory)",
795
+ "f / F · t filter by state, lens, severity, tier, doubted · clear it · step the tier filter (confirmed → likely → doubtful → unknown)",
796
+ "P the stage 2 plan: space toggles a row, ⏎ approves (hard stop = the kept total), Esc back",
797
+ "x / D stop the running scan (the ledger resumes it) · ask the companion for a delta re-scan (it shows the price first)",
798
+ "Ctrl-q release a focused pi pane or the companion column back to the board",
799
+ "",
800
+ "↑/↓ scroll when the terminal is short · any other key closes",
801
+ ];
802
+ // ---- live pi pane ----------------------------------------------------------
803
+ /** The viewer header after its name: where it is in the PR's logs, whether it
804
+ * follows the tail, and the keys that move it. */
805
+ function viewerHeaderTail(pane, viewer, focused) {
806
+ if (viewer.round === undefined)
807
+ return `${FG.dim} · no round log yet${RESET}`;
808
+ const round = `r${viewer.round}${viewer.rounds > 1 ? ` (${viewer.roundIndex}/${viewer.rounds})` : ""}${viewer.atLatest ? "" : " · past"}`;
809
+ const stream = `${viewer.stream}${viewer.streams > 1 ? ` (${viewer.streamIndex}/${viewer.streams})` : ""}`;
810
+ const state = pane.stale
811
+ ? "stale — refresh failing"
812
+ : viewer.live === true
813
+ ? "running"
814
+ : viewer.live === false
815
+ ? "settled"
816
+ : "";
817
+ const follow = pane.offset > 0
818
+ ? `${FG.accent} · ↑ ${pane.offset} rows back${RESET}${FG.dim} · End follows${RESET}`
819
+ : `${FG.dim} · following${RESET}`;
820
+ const keys = " · [ ] stream · < > round";
821
+ const mode = focused ? " · Ctrl-q back to board" : "";
822
+ return `${FG.dim} · ${round} · ${stream}${state ? ` · ${state}` : ""}${RESET}${follow}${FG.dim}${keys}${mode}${RESET}`;
823
+ }
824
+ /**
825
+ * Header of the pane: which session, whether it is live, whether it currently
826
+ * owns the keyboard, and how far back in scrollback it is parked.
827
+ */
828
+ export function piHeader(pr, pane, focused = false) {
829
+ if (pr === undefined)
830
+ return `${FG.dim}PI — no PR selected${RESET}`;
831
+ const mine = pane && pane.pr === pr ? pane : undefined;
832
+ // A pi terminal (a debug round's or a takeover's) names its tmux session;
833
+ // everything else is the PR's live transcript — there is no `pr-<n>` tmux
834
+ // session to name.
835
+ const session = mine?.viewer ? undefined : mine?.session;
836
+ const viewer = mine?.viewer;
837
+ const name = session === undefined
838
+ ? focused
839
+ ? `${ACCENT_BG}LIVE pr-${pr}${DRESET}`
840
+ : `${MUTED}LIVE ${DRESET}${ACCENT}pr-${pr}${DRESET}`
841
+ : focused
842
+ ? `${ACCENT_BG}PI ${session}${DRESET}`
843
+ : `${MUTED}PI ${DRESET}${ACCENT}${session}${DRESET}`;
844
+ if (!mine)
845
+ return `${name}${FG.dim} · connecting…${RESET}`;
846
+ if (viewer)
847
+ return `${name}${viewerHeaderTail(mine, viewer, focused)}`;
848
+ if (mine.missing) {
849
+ return `${name}${FG.dim} · no pi session for #${pr}${mine.stale ? " · (stale)" : ""}${RESET}`;
850
+ }
851
+ const scroll = mine.offset > 0
852
+ ? `${FG.accent} · ↑ ${mine.offset} lines back${RESET}${FG.dim} · End live${RESET}`
853
+ : "";
854
+ const mode = focused
855
+ ? `${FG.accent} · focused${RESET}${FG.dim} · Ctrl-q back to board${RESET}`
856
+ : `${FG.dim} · live mirror · click to type${RESET}`;
857
+ return `${name}${mode}${scroll}`;
858
+ }
859
+ /** The window of the capture that fits the region, already width-clamped.
860
+ * `pane.offset` parks the window that many lines above the live tail. */
861
+ export function piBody(pr, pane, width, height) {
862
+ if (pr === undefined || height <= 0)
863
+ return [];
864
+ const mine = pane && pane.pr === pr ? pane : undefined;
865
+ if (!mine)
866
+ return [`${FG.dim}waiting for the first capture…${RESET}`];
867
+ if (mine.lines.length === 0)
868
+ return mine.missing ? [] : [`${FG.dim}(pane empty)${RESET}`];
869
+ // Bottom-anchored, like the terminal it mirrors: new output lands on a
870
+ // stable edge instead of shifting the whole pane down. A scrollback offset
871
+ // moves that edge up through the captured history.
872
+ const src = mine.offset > 0
873
+ ? mine.lines.slice(0, Math.max(0, mine.lines.length - mine.offset))
874
+ : mine.lines;
875
+ const tail = src.slice(-height).map((l) => truncate(l, width));
876
+ return [...new Array(Math.max(0, height - tail.length)).fill(""), ...tail];
877
+ }
878
+ // ---- events overlay ---------------------------------------------------------
879
+ /** The demoted EVENTS strip: a floating, scrollable band over the board. */
880
+ function renderEventsOverlay(frame, view, cols, rows, barRows) {
881
+ const { top, height } = eventsOverlayBand(rows, barRows);
882
+ const visible = Math.max(0, height - 2);
883
+ // The band is opaque: whatever it paints over must not stay clickable
884
+ // underneath it (a hidden PR row, the pi pane's focus zone). Zones are
885
+ // clipped to the rows the band leaves visible; only event rows below are
886
+ // declared in its place.
887
+ const bandY1 = top + 1; // frame row → terminal y
888
+ const bandY2 = top + height;
889
+ frame.zones = frame.zones.flatMap((z) => {
890
+ if (z.y2 < bandY1 || z.y1 > bandY2)
891
+ return [z];
892
+ const kept = [];
893
+ if (z.y1 < bandY1)
894
+ kept.push({ ...z, y2: bandY1 - 1 });
895
+ if (z.y2 > bandY2)
896
+ kept.push({ ...z, y1: bandY2 + 1 });
897
+ return kept;
898
+ });
899
+ frame.set(top, rule(cols, "├", "┤", [
900
+ sectionTitle("EVENTS"),
901
+ `${MUTED}what the daemon just did${DRESET}`,
902
+ `${MUTED}j/k scroll · e/Esc close${DRESET}`,
903
+ ]));
904
+ const slice = view.events.slice(view.eventsScroll, view.eventsScroll + visible);
905
+ for (let i = 0; i < visible; i++) {
906
+ const e = slice[i];
907
+ const text = e
908
+ ? e.anomaly
909
+ ? `${FG.anomaly}${truncate(oneLine(e.text), cols - 4)}${RESET}`
910
+ : truncate(oneLine(e.text), cols - 4)
911
+ : "";
912
+ frame.boxRow(top + 1 + i, [{ text: ` ${text}`, width: cols - 2 }]);
913
+ const prMatch = e ? /#(\d+)/.exec(e.text) : null;
914
+ if (prMatch) {
915
+ frame.zones.push({
916
+ x1: 2,
917
+ y1: top + 1 + i + 1,
918
+ x2: cols - 1,
919
+ y2: top + 1 + i + 1,
920
+ action: { t: "event-jump", pr: Number(prMatch[1]) },
921
+ });
922
+ }
923
+ }
924
+ frame.set(top + height - 1, rule(cols, "├", "┤", []));
925
+ }
926
+ // ---- render ----------------------------------------------------------------
927
+ /**
928
+ * The draft as one paintable line of at most `width` cells: control bytes
929
+ * stripped, each newline shown as `⏎`, and — when it overflows — its END kept
930
+ * behind a `…`, because the end is where the operator types (the `▁` cursor).
931
+ */
932
+ function draftLine(text, width) {
933
+ const full = `${sanitizeText(text).replace(/\n/g, "⏎")}▁`;
934
+ if (displayWidth(full) <= width)
935
+ return full;
936
+ const chars = Array.from(full);
937
+ let tail = "";
938
+ let w = 0;
939
+ for (let i = chars.length - 1; i >= 0; i--) {
940
+ const cw = charWidth(chars[i].codePointAt(0) ?? 0);
941
+ if (w + cw > width - 1)
942
+ break;
943
+ tail = chars[i] + tail;
944
+ w += cw;
945
+ }
946
+ return `…${tail}`;
947
+ }
948
+ /** The input box's three rows: its target, the text being typed, its keys. */
949
+ function inputBoxLines(box, width) {
950
+ return [
951
+ ` ${HEADING}MSG → ${oneLine(box.target)}${DRESET}`,
952
+ ` > ${draftLine(box.text, Math.max(1, width - 3))}`,
953
+ ` ⏎ send · Esc cancel · Alt-⏎ newline`,
954
+ ];
955
+ }
956
+ /**
957
+ * The input box over the foot of a tab's own screen — the board paints it in
958
+ * its pi region, but a prompt a tab opens (a memory edit, a rejection reason)
959
+ * types into the same box and must be seen on that tab: a divider and the
960
+ * box's three rows, just above the frame's bottom border.
961
+ */
962
+ export function overlayInputBox(frame, box) {
963
+ const top = frame.rows - 5;
964
+ if (top < 1)
965
+ return;
966
+ frame.meta["inputBoxTop"] = top;
967
+ frame.meta["inputBoxBottom"] = top + 3;
968
+ frame.meta["inputBoxCols"] = frame.cols;
969
+ frame.set(top, `├${"─".repeat(Math.max(0, frame.cols - 2))}┤`);
970
+ inputBoxLines(box, frame.cols - 2).forEach((text, i) => frame.boxRow(top + 1 + i, [{ text, width: frame.cols - 2 }]));
971
+ }
972
+ export function renderBoard(view, cols, rows) {
973
+ const frame = new Frame(cols, rows);
974
+ const now = view.now ?? new Date();
975
+ frame.set(0, topBar(view, cols));
976
+ const az = alertZone(view, cols);
977
+ if (az)
978
+ frame.zones.push({
979
+ x1: az.x1,
980
+ y1: 1,
981
+ x2: az.x2,
982
+ y2: 1,
983
+ action: { t: "companion" },
984
+ });
985
+ const live = boardKeys(view);
986
+ const barRows = barHeight("board", cols, live.bar);
987
+ const pRows = piRows(rows, barRows);
988
+ const bodyRows = rows - 2 - barRows - pRows; // top bar + command bar + bottom border
989
+ const sorted = visiblePrs(view);
990
+ const listW = listWidth(sorted, cols, now);
991
+ const detailW = cols - 2 - listW - 1;
992
+ const selectedPr = sorted[view.selected];
993
+ frame.meta = { listW, bodyRows, piTop: 1 + bodyRows, piRows: pRows };
994
+ if (view.help) {
995
+ frame.boxRow(1, [
996
+ { text: ` ${sectionTitle("KEYS", "everything the TUI answers to")}`, width: cols - 2 },
997
+ ]);
998
+ const helpRows = Math.max(0, rows - 3);
999
+ const helpMax = Math.max(0, HELP_LINES.length - helpRows);
1000
+ const helpTop = Math.min(Math.max(0, view.helpScroll ?? 0), helpMax);
1001
+ frame.meta["helpMax"] = helpMax;
1002
+ HELP_LINES.slice(helpTop, helpTop + helpRows).forEach((l, i) => {
1003
+ frame.boxRow(2 + i, [{ text: ` ${l}`, width: cols - 2 }]);
1004
+ });
1005
+ for (let r = 2 + Math.min(HELP_LINES.length - helpTop, helpRows); r < rows - 1; r++)
1006
+ frame.boxRow(r, [{ text: "", width: cols - 2 }]);
1007
+ frame.set(rows - 1, rule(cols, "└", "┘", []));
1008
+ return frame;
1009
+ }
1010
+ // Board body: list | detail.
1011
+ //
1012
+ // A snapshot that never arrived is unknown, not empty. The count
1013
+ // reads `?`, the rows are replaced by the reason and the remedy, and the
1014
+ // detail pane says "no data" rather than "no PR selected".
1015
+ const known = view.snapshot !== undefined;
1016
+ const flabel = filterLabel(view.boardFilter);
1017
+ const listLines = known
1018
+ ? [section(`PRS (${sorted.length})`, flabel !== "" ? flabel : "the daemon's live set")]
1019
+ : [
1020
+ section("PRS (?)", "unknown — the daemon has not answered"),
1021
+ ...unknownSourceLines(view.connection, listW - 1),
1022
+ ];
1023
+ // The list scrolls with the selection: the verbs act on the selected PR, so
1024
+ // it must never sit off-screen (`windowStart`, the tabs' shared rule). The
1025
+ // header stays put; the last body row is the legend, painted over whatever
1026
+ // would sit there, so the PR slots are the rows between the two.
1027
+ const prSlots = Math.max(1, bodyRows - 1 - listLines.length);
1028
+ const start = windowStart(view.selected, sorted.length, prSlots);
1029
+ sorted.slice(start, start + prSlots).forEach((pr, offset) => {
1030
+ const i = start + offset;
1031
+ listLines.push(styledRow(pr, i === view.selected, listW - 1, now, view.repo));
1032
+ const y = 1 + listLines.length - 1 + 1; // frame row of this PR line (below top bar)
1033
+ // Only painted rows get zones: with a long list, off-screen rows would
1034
+ // otherwise leave phantom click targets over the pi region and the
1035
+ // bar-row gaps — a click there could select (or double-click into the
1036
+ // pi pane of) an invisible PR. The slice above holds only painted rows,
1037
+ // but a body too short for even one slot must still declare nothing.
1038
+ if (listLines.length > bodyRows - 1)
1039
+ return;
1040
+ frame.zones.push({
1041
+ x1: 2,
1042
+ y1: y,
1043
+ x2: listW,
1044
+ y2: y,
1045
+ action: { t: "select-pr", pr: pr.number },
1046
+ });
1047
+ frame.zones.push({
1048
+ x1: 4,
1049
+ y1: y,
1050
+ x2: 4 + String(pr.number).length + 1,
1051
+ y2: y,
1052
+ action: { t: "open-github", pr: pr.number },
1053
+ });
1054
+ });
1055
+ const progressRows = [];
1056
+ const dLines = known
1057
+ ? detailLines(view.detail, selectedPr, detailW - 2, now, view.progress?.pr === selectedPr?.number ? view.progress : undefined, progressRows)
1058
+ : unknownDetailLines(view.connection, detailW - 2);
1059
+ // With the transcript viewer in the pane, a lens row of the progress panel is
1060
+ // a click target: it selects that lens's transcript. A painted row only (an
1061
+ // off-screen one would be a phantom target), and only while the viewer is up.
1062
+ if (view.pi?.viewer && view.pi.pr === selectedPr?.number) {
1063
+ for (const row of progressRows) {
1064
+ if (row.line >= bodyRows)
1065
+ continue;
1066
+ frame.zones.push({
1067
+ x1: listW + 3,
1068
+ y1: row.line + 2,
1069
+ x2: cols - 1,
1070
+ y2: row.line + 2,
1071
+ action: { t: "viewer-lens", lens: row.lens, nth: row.nth },
1072
+ });
1073
+ }
1074
+ }
1075
+ for (let r = 0; r < bodyRows; r++) {
1076
+ const isLegendRow = r === bodyRows - 1;
1077
+ frame.boxRow(1 + r, [
1078
+ { text: isLegendRow ? ` ${legendLine()}` : ` ${listLines[r] ?? ""}`, width: listW },
1079
+ { text: ` ${dLines[r] ?? ""}`, width: detailW },
1080
+ ]);
1081
+ }
1082
+ // Live pi mirror (or the quick-message input box) — the lower region.
1083
+ const piTop = 1 + bodyRows;
1084
+ const piLines = Math.max(0, pRows - 2); // the region is divider + header + lines
1085
+ const panePr = view.piPr ?? selectedPr?.number;
1086
+ const piFocused = view.piFocus === true && panePr !== undefined;
1087
+ if (pRows > 0) {
1088
+ // Focused, the divider is drawn heavy and accented — the pane visibly
1089
+ // becomes its own window rather than a strip of the board.
1090
+ const bar = piFocused ? "━" : "─";
1091
+ const inner = `${fit(bar.repeat(listW), listW)}${piFocused ? bar : "┴"}${bar.repeat(detailW)}`;
1092
+ frame.set(piTop, `│${piFocused ? `${FG.accent}${inner}${RESET}` : inner}│`);
1093
+ }
1094
+ if (view.inputBox) {
1095
+ inputBoxLines(view.inputBox, cols - 2).forEach((text, i) => frame.boxRow(piTop + 1 + i, [{ text, width: cols - 2 }]));
1096
+ for (let i = 4; i < pRows; i++)
1097
+ frame.boxRow(piTop + i, [{ text: "", width: cols - 2 }]);
1098
+ }
1099
+ else if (pRows > 0) {
1100
+ frame.boxRow(piTop + 1, [
1101
+ {
1102
+ text: ` ${piHeader(panePr, view.pi, piFocused)}${view.noticeLine ? ` ${view.noticeLine}` : ""}`,
1103
+ width: cols - 2,
1104
+ },
1105
+ ]);
1106
+ // Width comes from piPaneSize so the rectangle tmux is resized to and the
1107
+ // rectangle the capture is painted into cannot drift apart.
1108
+ const paneCols = piPaneSize(cols, rows, barRows)?.cols ?? 0;
1109
+ // The viewer keeps its last row for its input line (the PR-pane rule): the
1110
+ // transcript above it, so a mirror's rows are untouched.
1111
+ const line = piLines > 1 && view.pi?.viewer && view.pi.pr === panePr && view.viewerInput?.pr === panePr
1112
+ ? view.viewerInput
1113
+ : undefined;
1114
+ const bodyLines = line ? piLines - 1 : piLines;
1115
+ const body = piBody(panePr, view.pi, paneCols, bodyLines);
1116
+ for (let i = 0; i < bodyLines; i++)
1117
+ frame.boxRow(piTop + 2 + i, [{ text: ` ${body[i] ?? ""}`, width: cols - 2 }]);
1118
+ if (line)
1119
+ frame.boxRow(piTop + 2 + bodyLines, [
1120
+ { text: ` ${viewerInputRow(line, paneCols)}`, width: cols - 2 },
1121
+ ]);
1122
+ // Clicking anywhere in the region (divider, header or body) gives the pane
1123
+ // the keyboard, in place — nothing on the board takes the whole terminal.
1124
+ if (panePr !== undefined) {
1125
+ frame.zones.push({
1126
+ x1: 2,
1127
+ y1: piTop + 1,
1128
+ x2: cols - 1,
1129
+ y2: piTop + pRows,
1130
+ action: { t: "pi-focus" },
1131
+ });
1132
+ }
1133
+ }
1134
+ // EVENTS: a floating overlay on `e`.
1135
+ // The quick-message editor owns the keyboard while open, so it stays visible.
1136
+ if (view.eventsFocus && !view.inputBox)
1137
+ renderEventsOverlay(frame, view, cols, rows, barRows);
1138
+ // The shared command bar: exactly the verbs this frame answers to.
1139
+ paintCmdBar(frame, "board", cols, rows, live.bar);
1140
+ frame.set(rows - 1, rule(cols, "└", "┘", []));
1141
+ return frame;
1142
+ }
1143
+ //# sourceMappingURL=board.js.map