@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,1095 @@
1
+ import { deliverConfigChange, configDeliveryChecks } from "./configdelivery.js";
2
+ import type { TransportOptions } from "./transport.js";
3
+ // LLM auth — the wizard's credential choice.
4
+ // Both routes are first-class and the trade is stated honestly:
5
+ //
6
+ // OAuth (a ChatGPT subscription) — the shipped default. pi's tokens live in
7
+ // `auth.json` under the pi home of the process that logged in, and they do
8
+ // NOT transfer between the host and the containers. So the OAuth route
9
+ // costs up to THREE separate browser logins: this wizard's own pi session
10
+ // (on the image route, `qcr login` into the `qcr-login` volume), the daemon
11
+ // container, and the companion container. Each container login must land
12
+ // on that container's named pi-home volume (the daemon's is `qcr-pihome`,
13
+ // mounted at /home/qcr/.pi in the released image) or a recreate silently
14
+ // costs it — this step verifies exactly that, per surface, at the moment
15
+ // the surface exists.
16
+ // API key — one paste covers the daemon and its review sessions at once (the
17
+ // daemon container's entrypoint exports the secrets-dir file as
18
+ // OPENAI_API_KEY for every pi process in it), and every model string must
19
+ // move from the OAuth provider prefix to the API one. The key file reaches
20
+ // no other process: the companion container is never handed it, so the
21
+ // companion keeps its own login (its model is on the OAuth provider by
22
+ // default), and this host's own pi reads OPENAI_API_KEY only from its own
23
+ // environment.
24
+ // The wizard does that rewrite itself: five values, comment-preserving,
25
+ // idempotent, and reversible, so switching routes later re-runs cleanly in
26
+ // either direction.
27
+ //
28
+ // Neither route needs anything for memory embeddings: the memory
29
+ // engine embeds LOCALLY by default, and `openai_api_key` is pi's credential
30
+ // alone — the hosted-embeddings opt-in is the embeddings step (38) with its
31
+ // OWN key file. This step says so once, as a note, so an operator on the OAuth
32
+ // route is not left wondering what the key file would have covered.
33
+ //
34
+ // House rule, structural here: NO credential value ever reaches an argv. The
35
+ // key is written straight to the secrets file (0600, dir 0700) by this module,
36
+ // or collected by `deploy/collect-secrets.sh` — never passed to a process, and
37
+ // never echoed into a check detail, the checklist, or a tool result. In the
38
+ // pi-driven flow the wizard has no prompter at all, so the LLM never even sees
39
+ // the key: the step points at the shell wizard and then verifies the file.
40
+ //
41
+ // Deterministic by construction: config and secrets are plain files under
42
+ // paths derived from the injected state dir, every docker probe goes through
43
+ // the ProcessRunner seam, and verify() neither prompts nor writes.
44
+ import {
45
+ chmodSync,
46
+ copyFileSync,
47
+ existsSync,
48
+ mkdirSync,
49
+ readFileSync,
50
+ writeFileSync,
51
+ } from "node:fs";
52
+ import { homedir } from "node:os";
53
+ import { dirname, isAbsolute, join } from "node:path";
54
+ import { COMPANION_DEFAULTS, TUI_DEFAULTS } from "../../config.js";
55
+ import { locateSecrets } from "../../install.js";
56
+ import { CHOICE_KEYS, AUTH_ROUTES, authRouteOf, type AuthRoute } from "../choices.js";
57
+ import type {
58
+ CheckResult,
59
+ OnboardAdapters,
60
+ OnboardingStep,
61
+ ProcessRunner,
62
+ StepContext,
63
+ StepReport,
64
+ } from "../engine.js";
65
+ import { DAEMON_SERVICE, composeArgs, rootOf, writeAtomic } from "./compose.js";
66
+ import { readTomlKey, tomlScalarText } from "./ingress.js";
67
+ import { sshArgv } from "./ssh.js";
68
+ import { topologyOf } from "./topology.js";
69
+ import { remoteFactsFor } from "./transport.js";
70
+
71
+ export const LLM_AUTH_STEP_ID = "llm_auth";
72
+ /** The choice key later steps read the route from. */
73
+ export const AUTH_ROUTE_CHOICE_KEY = CHOICE_KEYS.authRoute;
74
+ /** The choice key carrying the provider prefix the config now uses. */
75
+ export const MODEL_PREFIX_CHOICE_KEY = "llm_model_prefix";
76
+
77
+ export type { AuthRoute };
78
+
79
+ /** pi's ChatGPT-OAuth provider prefix (config.example.toml's shipped default). */
80
+ export const OAUTH_PREFIX = "openai-codex/";
81
+ /** pi's direct-API provider prefix — needs OPENAI_API_KEY. */
82
+ export const API_PREFIX = "openai/";
83
+
84
+ export function prefixFor(route: AuthRoute): string {
85
+ return route === "oauth" ? OAUTH_PREFIX : API_PREFIX;
86
+ }
87
+
88
+ /** The secrets-dir file name — the same one `deploy/collect-secrets.sh` writes
89
+ * and the container entrypoints export as OPENAI_API_KEY. */
90
+ export const OPENAI_KEY_FILE = "openai_api_key";
91
+
92
+ /**
93
+ * The FIVE model strings the route decides. Every one of them lives in
94
+ * `config.toml [models]` / `[models.tiers]` (docs/llm-setup.md route 2), and
95
+ * the provider prefix IS the route — nothing else in the file changes.
96
+ */
97
+ export const MODEL_LOCATIONS: ReadonlyArray<{ section: string; key: string }> = [
98
+ { section: "models", key: "default" },
99
+ { section: "models", key: "conversation" },
100
+ { section: "models.tiers", key: "terra-med" },
101
+ { section: "models.tiers", key: "sol-med" },
102
+ { section: "models.tiers", key: "sol-high" },
103
+ ];
104
+
105
+ /** "models.default", "models.tiers.sol-high", … — the stable labels the checks
106
+ * and the checklist record use. */
107
+ export function modelLabels(): string[] {
108
+ return MODEL_LOCATIONS.map((l) => `${l.section}.${l.key}`);
109
+ }
110
+
111
+ // ---- paths ------------------------------------------------------------------
112
+
113
+ export function configExamplePathFor(stateDir: string): string {
114
+ return join(dirname(stateDir), "config.example.toml");
115
+ }
116
+
117
+ export function expandHomePath(path: string, home: string): string {
118
+ if (path === "~") return home;
119
+ if (path.startsWith("~/")) return join(home, path.slice(2));
120
+ return path;
121
+ }
122
+
123
+ /** The host pi's OAuth token store — this wizard's own login (pi keeps it at
124
+ * `$HOME/.pi/agent/auth.json`). */
125
+ export function hostAuthJsonPath(home: string): string {
126
+ return join(home, ".pi", "agent", "auth.json");
127
+ }
128
+
129
+ /** pi's provider key for the ChatGPT-OAuth route — the `openai-codex/` prefix
130
+ * without its slash, and the entry pi writes into auth.json on /login. */
131
+ const OAUTH_PROVIDER = OAUTH_PREFIX.replace(/\/$/, "");
132
+
133
+ /** Does this host's auth.json hold a ChatGPT (openai-codex) OAuth login? The
134
+ * file existing proves nothing: pi keeps every provider's login there, and a
135
+ * logged-out pi can leave `{}` behind. Unreadable or malformed ⇒ false. */
136
+ export function hostHasOAuthLogin(authPath: string): boolean {
137
+ try {
138
+ const parsed = JSON.parse(readFileSync(authPath, "utf8")) as Record<string, unknown>;
139
+ const cred = parsed?.[OAUTH_PROVIDER] as Record<string, unknown> | undefined;
140
+ return typeof cred === "object" && cred !== null && cred.type === "oauth";
141
+ } catch {
142
+ return false;
143
+ }
144
+ }
145
+
146
+ function hostHome(): string {
147
+ return process.env.HOME ?? homedir();
148
+ }
149
+
150
+ // ---- tolerant TOML reads ----------------------------------------------------
151
+
152
+ const SECTION_RE = /^\s*\[([^\]]+)\]\s*(?:#.*)?$/;
153
+ // key = "value" or key = 'value' — the key may be bare or quoted (TOML allows
154
+ // both for the dashed tier names); the value is a basic or a literal string,
155
+ // single- or triple-quoted, as the loader reads any of them. Trailing text (a comment) is preserved verbatim.
156
+ const STRING_KV_RE = /^(\s*)("?)([A-Za-z0-9_.-]+)\2(\s*=\s*)("""|'''|"|')(.*?)\5(.*)$/;
157
+
158
+ /** The string value an STRING_KV_RE match carries, whichever quote it used. */
159
+ function kvValue(kv: RegExpExecArray): string {
160
+ return kv[6]!;
161
+ }
162
+
163
+ function isComment(line: string): boolean {
164
+ return /^\s*#/.test(line);
165
+ }
166
+
167
+ /** Read one string value out of raw config text. Tolerant on purpose: the
168
+ * wizard reads a half-filled config (FILL values everywhere) that the strict
169
+ * loader would refuse. Returns null when absent. */
170
+ export function readTomlString(text: string, section: string, key: string): string | null {
171
+ let current = "";
172
+ for (const line of text.split("\n")) {
173
+ const sec = SECTION_RE.exec(line);
174
+ if (sec) {
175
+ current = sec[1]!.trim();
176
+ continue;
177
+ }
178
+ if (isComment(line) || current !== section) continue;
179
+ const kv = STRING_KV_RE.exec(line);
180
+ if (kv && kv[3] === key) {
181
+ // A basic string's escapes decode as readTomlKey decodes them.
182
+ if (kv[5] === '"')
183
+ return tomlScalarText(
184
+ line.slice(kv[1]!.length + kv[2]!.length + kv[3].length + kv[2]!.length + kv[4]!.length),
185
+ );
186
+ return kvValue(kv);
187
+ }
188
+ }
189
+ return null;
190
+ }
191
+
192
+ /** Where the secrets live: `[github] secrets_dir` wins (it is what the daemon
193
+ * and the compose mount actually use), then $QC_SECRETS_DIR, then the install
194
+ * locator's answer — `<config home>/secrets`: the same answer the
195
+ * daemon's loader reaches. The value is read the way every other onboarding
196
+ * step reads it (`readTomlKey`: basic or literal string), so a single-quoted
197
+ * secrets_dir names the same directory here as in memory and bring-up. */
198
+ export function resolveSecretsDir(
199
+ configText: string,
200
+ home: string,
201
+ envDir?: string,
202
+ root?: string,
203
+ ): string {
204
+ const located = locateSecrets({
205
+ configured: readTomlKey(configText, "github", "secrets_dir"),
206
+ override: envDir,
207
+ env: { ...process.env, HOME: home },
208
+ }).path;
209
+ // A relative answer is rooted at the sandbox, as every other step roots it —
210
+ // never at the wizard's cwd.
211
+ return root !== undefined && !isAbsolute(located) ? join(root, located) : located;
212
+ }
213
+
214
+ // ---- the model-string rewrite ----------------------------------------------
215
+
216
+ export interface ModelAudit {
217
+ /** "models.default" … */
218
+ label: string;
219
+ value: string;
220
+ /** "oauth" | "api" | "custom" (some other provider — not ours to touch) |
221
+ * "missing" (the key is not in the file). */
222
+ kind: AuthRoute | "custom" | "missing";
223
+ }
224
+
225
+ /** Which managed route a model string is on, and the model after the prefix;
226
+ * null for any other provider (not ours to touch). The one classification the
227
+ * audit and the rewrite share. */
228
+ export function managedModel(value: string): { route: AuthRoute; rest: string } | null {
229
+ for (const route of AUTH_ROUTES) {
230
+ const prefix = prefixFor(route);
231
+ if (value.startsWith(prefix)) return { route, rest: value.slice(prefix.length) };
232
+ }
233
+ return null;
234
+ }
235
+
236
+ /** What the five locations currently say. Read-only; the basis of verify(). */
237
+ export function auditModelStrings(text: string): ModelAudit[] {
238
+ return MODEL_LOCATIONS.map(({ section, key }) => {
239
+ const label = `${section}.${key}`;
240
+ const value = readTomlString(text, section, key);
241
+ if (value === null) return { label, value: "", kind: "missing" as const };
242
+ return { label, value, kind: managedModel(value)?.route ?? ("custom" as const) };
243
+ });
244
+ }
245
+
246
+ export interface RewriteResult {
247
+ text: string;
248
+ /** Labels whose prefix changed in this pass. */
249
+ rewritten: string[];
250
+ /** Labels already on the target prefix (idempotent re-run ⇒ all five). */
251
+ unchanged: string[];
252
+ /** Labels on some other provider — left exactly as they are. */
253
+ custom: string[];
254
+ /** Labels not present in the file at all. */
255
+ missing: string[];
256
+ }
257
+
258
+ /**
259
+ * Move every one of the five model strings onto `route`'s provider prefix.
260
+ *
261
+ * Line-oriented on purpose: comments, ordering, spacing and every other key in
262
+ * the file survive byte-for-byte (a TOML round-trip would eat them). Only the
263
+ * prefix of the five values changes, so the operation is idempotent (running it
264
+ * twice is a no-op) and reversible (oauth → api → oauth restores the original
265
+ * bytes). Values on any other provider are left alone — a deliberate custom
266
+ * model is not the wizard's business.
267
+ */
268
+ export function rewriteModelPrefixes(text: string, route: AuthRoute): RewriteResult {
269
+ const target = prefixFor(route);
270
+ const wanted = new Map(MODEL_LOCATIONS.map((l) => [`${l.section}.${l.key}`, l]));
271
+ const seen = new Set<string>();
272
+ const rewritten: string[] = [];
273
+ const unchanged: string[] = [];
274
+ const custom: string[] = [];
275
+
276
+ const lines = text.split("\n");
277
+ let current = "";
278
+ for (let i = 0; i < lines.length; i += 1) {
279
+ const line = lines[i]!;
280
+ const sec = SECTION_RE.exec(line);
281
+ if (sec) {
282
+ current = sec[1]!.trim();
283
+ continue;
284
+ }
285
+ if (isComment(line)) continue;
286
+ const kv = STRING_KV_RE.exec(line);
287
+ if (!kv) continue;
288
+ const label = `${current}.${kv[3]!}`;
289
+ if (!wanted.has(label) || seen.has(label)) continue;
290
+ seen.add(label);
291
+ const value = kvValue(kv);
292
+ const managed = managedModel(value);
293
+ if (managed === null) {
294
+ custom.push(label);
295
+ continue;
296
+ }
297
+ const next = `${target}${managed.rest}`;
298
+ if (next === value) {
299
+ unchanged.push(label);
300
+ continue;
301
+ }
302
+ const quote = kv[5]!;
303
+ lines[i] = `${kv[1]!}${kv[2]!}${kv[3]!}${kv[2]!}${kv[4]!}${quote}${next}${quote}${kv[7]!}`;
304
+ rewritten.push(label);
305
+ }
306
+
307
+ const missing = modelLabels().filter((l) => !seen.has(l));
308
+ return { text: lines.join("\n"), rewritten, unchanged, custom, missing };
309
+ }
310
+
311
+ // ---- the API key ------------------------------------------------------------
312
+
313
+ /**
314
+ * The same shape `deploy/collect-secrets.sh`'s `v_openai` asserts (`^sk-`),
315
+ * plus "one unbroken string" — the shell's hidden single-line read cannot
316
+ * produce whitespace anyway. Pinned against the shell by
317
+ * tests/onboard-llmauth.test.ts so the two validators cannot drift.
318
+ */
319
+ export function validateOpenAiKey(value: string): boolean {
320
+ const v = value.trim();
321
+ return v.startsWith("sk-") && v.length > 3 && !/\s/.test(v);
322
+ }
323
+
324
+ export interface KeyFileState {
325
+ present: boolean;
326
+ valid: boolean;
327
+ path: string;
328
+ }
329
+
330
+ export function readKeyFileState(secretsDir: string): KeyFileState {
331
+ const path = join(secretsDir, OPENAI_KEY_FILE);
332
+ if (!existsSync(path)) return { present: false, valid: false, path };
333
+ let raw = "";
334
+ try {
335
+ raw = readFileSync(path, "utf8");
336
+ } catch {
337
+ return { present: true, valid: false, path };
338
+ }
339
+ return { present: raw.trim().length > 0, valid: validateOpenAiKey(raw), path };
340
+ }
341
+
342
+ /** Write the key exactly the way the shell wizard does: dir 0700, file 0600,
343
+ * no trailing newline, and the value never leaves this function. */
344
+ export function writeKeyFile(secretsDir: string, value: string): string {
345
+ mkdirSync(secretsDir, { recursive: true, mode: 0o700 });
346
+ chmodSync(secretsDir, 0o700);
347
+ const path = join(secretsDir, OPENAI_KEY_FILE);
348
+ writeFileSync(path, value.trim(), { mode: 0o600 });
349
+ chmodSync(path, 0o600);
350
+ return path;
351
+ }
352
+
353
+ // ---- container login verification -------------------------------------------
354
+
355
+ export type LoginState =
356
+ "absent" | "no-pi-volume" | "stopped" | "no-auth" | "wrong-provider" | "ok" | "undetectable";
357
+
358
+ /**
359
+ * The in-container login check: the same question `hostHasOAuthLogin` asks of
360
+ * the host — is there an `openai-codex` entry of type `oauth`? — asked by the
361
+ * container's own node, so only an exit code ever leaves it (never a token,
362
+ * which on the VM route would otherwise cross ssh). Exit 0 = logged in,
363
+ * 3 = no auth.json / empty, 4 = an auth.json without that login (`{}`, or
364
+ * another provider picked at pi's /login menu). Anything else (no node) is
365
+ * undetectable, never a pass.
366
+ */
367
+ export const CONTAINER_LOGIN_SCRIPT =
368
+ "const fs=require('fs');let t='';try{t=fs.readFileSync(process.argv[1],'utf8')}catch{process.exit(3)}" +
369
+ "if(!t.trim())process.exit(3);let a;try{a=JSON.parse(t)}catch{process.exit(4)}" +
370
+ `const c=a&&a[${JSON.stringify(OAUTH_PROVIDER)}];process.exit(c&&typeof c==='object'&&c.type==='oauth'?0:4)`;
371
+
372
+ export interface LoginProbe {
373
+ state: LoginState;
374
+ /** The pi-home mount destination inside the container, when there is one. */
375
+ destination?: string;
376
+ /** Mount type + name, for the durability claim. */
377
+ mount?: string;
378
+ }
379
+
380
+ /**
381
+ * Did a pi OAuth login actually land on this container's PERSISTENT pi home?
382
+ *
383
+ * The question is deliberately asked about the MOUNT, not about `$HOME`: a
384
+ * container whose HOME has drifted off the mounted volume has pi write a
385
+ * perfectly good auth.json into the writable layer, and every recreate
386
+ * silently costs the login. Testing `<mount destination>/agent/
387
+ * auth.json` proves the token is on the volume, which is the only claim worth
388
+ * making. Never throws, never prompts: an undetectable docker is a note.
389
+ */
390
+ export async function probeContainerLogin(
391
+ runner: ProcessRunner,
392
+ container: string,
393
+ ): Promise<LoginProbe> {
394
+ const mounts = await runner.run("docker", ["inspect", "--format", "{{json .Mounts}}", container]);
395
+ if (mounts.code !== 0) {
396
+ const err = `${mounts.stderr}${mounts.stdout}`;
397
+ // "No such object" is a container that does not exist yet (the normal case
398
+ // before bring-up); anything else means we could not look.
399
+ return { state: /no such object|no such container/i.test(err) ? "absent" : "undetectable" };
400
+ }
401
+ let parsed: unknown;
402
+ try {
403
+ parsed = JSON.parse(mounts.stdout.trim() || "[]");
404
+ } catch {
405
+ return { state: "undetectable" };
406
+ }
407
+ const list = Array.isArray(parsed) ? (parsed as Array<Record<string, unknown>>) : [];
408
+ const piMount = list.find(
409
+ (m) => typeof m.Destination === "string" && /\/\.pi$/.test(m.Destination),
410
+ );
411
+ if (!piMount) return { state: "no-pi-volume" };
412
+ const destination = String(piMount.Destination);
413
+ const mount =
414
+ `${String(piMount.Type ?? "mount")} ${String(piMount.Name ?? piMount.Source ?? "")}`.trim();
415
+
416
+ const running = await runner.run("docker", [
417
+ "inspect",
418
+ "--format",
419
+ "{{.State.Running}}",
420
+ container,
421
+ ]);
422
+ if (running.code !== 0 || running.stdout.trim() !== "true")
423
+ return { state: "stopped", destination, mount };
424
+
425
+ const auth = await runner.run("docker", [
426
+ "exec",
427
+ container,
428
+ "node",
429
+ "-e",
430
+ CONTAINER_LOGIN_SCRIPT,
431
+ `${destination}/agent/auth.json`,
432
+ ]);
433
+ const state: LoginState =
434
+ auth.code === 0
435
+ ? "ok"
436
+ : auth.code === 3
437
+ ? "no-auth"
438
+ : auth.code === 4
439
+ ? "wrong-provider"
440
+ : "undetectable";
441
+ return { state, destination, mount };
442
+ }
443
+
444
+ /** How an operator reaches a container's pi login: a tmux attach ends with a
445
+ * detach; a command that runs pi itself (the daemon's login entrypoint) ends
446
+ * when pi exits. */
447
+ interface LoginRoute {
448
+ command: string;
449
+ tmux: boolean;
450
+ }
451
+
452
+ function loginSteps(route: LoginRoute): string {
453
+ return route.tmux
454
+ ? `${route.command} → /login → detach (Ctrl-b d)`
455
+ : `${route.command} → finish the browser login in pi, then exit pi`;
456
+ }
457
+
458
+ function loginCheck(
459
+ name: string,
460
+ label: string,
461
+ route: LoginRoute,
462
+ probe: LoginProbe,
463
+ ): CheckResult {
464
+ const steps = loginSteps(route);
465
+ switch (probe.state) {
466
+ case "ok":
467
+ return {
468
+ name,
469
+ ok: true,
470
+ detail: `${label}: logged in — auth.json is on the persistent pi home (${probe.mount}) at ${probe.destination}, so a container recreate keeps it`,
471
+ };
472
+ case "no-auth":
473
+ return {
474
+ name,
475
+ ok: false,
476
+ detail:
477
+ `${label}: no auth.json on the pi home (${probe.mount}). Attach and log in: ` +
478
+ `${steps}. ` +
479
+ "Host tokens do not transfer — this container needs its own login.",
480
+ };
481
+ case "wrong-provider":
482
+ return {
483
+ name,
484
+ ok: false,
485
+ detail:
486
+ `${label}: auth.json on the pi home (${probe.mount}) holds no ChatGPT (${OAUTH_PROVIDER}) OAuth login — ` +
487
+ "a /login to another provider does not count. Attach and log in with the ChatGPT option: " +
488
+ `${steps}.`,
489
+ };
490
+ case "no-pi-volume":
491
+ return {
492
+ name,
493
+ ok: false,
494
+ detail:
495
+ `${label}: the container has no volume mounted on its pi home, so any /login would live in the writable layer ` +
496
+ "and vanish on the next recreate. Recreate it with its pihome volume before logging in.",
497
+ };
498
+ case "stopped":
499
+ return {
500
+ name,
501
+ ok: true,
502
+ detail: `${label}: container exists but is not running — its login is verified when it starts`,
503
+ };
504
+ case "undetectable":
505
+ return {
506
+ name,
507
+ ok: true,
508
+ detail: `${label}: could not inspect docker from here — this login is verified where the container runs`,
509
+ };
510
+ case "absent":
511
+ default:
512
+ return {
513
+ name,
514
+ ok: true,
515
+ detail: `${label}: no container yet — this browser login is guided at the moment the container first needs it (tokens never transfer from this host)`,
516
+ };
517
+ }
518
+ }
519
+
520
+ /** The command that attaches to a tmux session in a container on this machine. */
521
+ function localAttach(container: string, session: string): string {
522
+ return `docker exec -it ${container} tmux attach -t ${session}`;
523
+ }
524
+
525
+ /** The command that opens pi in the daemon container with `/login` typed for
526
+ * the operator: the release image has no pi on the PATH and the daemon hosts no
527
+ * tmux session, so the login is the image's own `login` entrypoint mode. */
528
+ function daemonLoginCommand(container: string): string {
529
+ return `docker exec -it ${container} /opt/qcr/docker/entrypoint.sh login`;
530
+ }
531
+
532
+ /** Container names to probe, config first so a renamed deployment still works;
533
+ * the fallbacks are the loader's own defaults. */
534
+ export function daemonContainerName(configText: string): string {
535
+ return readTomlString(configText, "tui", "container")?.trim() || TUI_DEFAULTS.container;
536
+ }
537
+
538
+ /**
539
+ * The daemon container on this machine. The shipped compose file sets no
540
+ * `container_name`, so compose names it after the project
541
+ * (`<project>-daemon-1`), never the `[tui] container` the VM uses: ask compose
542
+ * first; when it names none (no compose stack here, or no daemon container
543
+ * yet) the configured name is probed.
544
+ */
545
+ async function localDaemonContainer(
546
+ runner: ProcessRunner,
547
+ root: string,
548
+ configText: string,
549
+ ): Promise<string> {
550
+ const ps = await runner.run(
551
+ "docker",
552
+ composeArgs(root, ["ps", "--all", "--format", "{{.Name}}", DAEMON_SERVICE]),
553
+ );
554
+ if (ps.code === 0) {
555
+ const name = ps.stdout
556
+ .split("\n")
557
+ .map((l) => l.trim())
558
+ .find((l) => l !== "");
559
+ if (name) return name;
560
+ }
561
+ return daemonContainerName(configText);
562
+ }
563
+
564
+ export function companionContainerName(configText: string): string {
565
+ return (
566
+ readTomlString(configText, "companion", "container_name")?.trim() ||
567
+ COMPANION_DEFAULTS.container_name
568
+ );
569
+ }
570
+
571
+ /** The companion's tmux session — where its pi, and so its /login, runs. */
572
+ export function companionSessionName(configText: string): string {
573
+ return readTomlString(configText, "companion", "session")?.trim() || COMPANION_DEFAULTS.session;
574
+ }
575
+
576
+ // ---- the operator-facing text ----------------------------------------------
577
+
578
+ export const ROUTE_QUESTION =
579
+ "How should the review sessions authenticate to OpenAI?\n" +
580
+ " 1) oauth — a ChatGPT subscription. Cost is your plan, flat. The catch: pi's OAuth tokens live in the\n" +
581
+ " pi home of whichever process logged in and DO NOT transfer between this host and the containers, so\n" +
582
+ " expect up to three separate browser logins — this wizard's pi session, the daemon container, and the\n" +
583
+ " companion container. Each is guided when its surface first needs it.\n" +
584
+ " 2) api — one OpenAI API key, metered per token. One paste covers the daemon and its review sessions (the daemon\n" +
585
+ " container's entrypoint exports the key file as OPENAI_API_KEY), and the wizard rewrites all five model strings\n" +
586
+ " for you. The companion container is not handed the key: it keeps its own login.\n" +
587
+ "Answer 1/oauth or 2/api:";
588
+
589
+ export const KEY_QUESTION = `paste the OpenAI API key (it is written straight to the ${OPENAI_KEY_FILE} secrets file, 0600, never to a command line):`;
590
+
591
+ export const EMBEDDINGS_NOTE =
592
+ "memory embeddings need nothing from this step: the memory engine embeds LOCALLY by default, inside the memory " +
593
+ "container, so no memory text leaves the machine on either route. openai_api_key is pi's model credential alone and " +
594
+ "is never read for embeddings; a hosted embedder is a separate, explicit opt-in (the embeddings step, order 38) with " +
595
+ "its own openai_embeddings_api_key file.";
596
+
597
+ export const STEP_EXPLAIN =
598
+ "Chooses how the review sessions talk to OpenAI, and makes the whole installation consistent with that choice. " +
599
+ "OAuth (a ChatGPT subscription) is flat-cost but costs up to three separate browser logins — this wizard's pi " +
600
+ "session, the daemon container and the companion container — because pi's tokens do not transfer between the host " +
601
+ "and a container; each login is guided where it happens and verified to have landed on that container's persistent " +
602
+ "pi-home volume, so a recreate never silently costs it. An API key is one paste that covers the daemon and its review " +
603
+ "sessions (the companion container is not handed the key and keeps its own login), " +
604
+ "and the wizard then rewrites all five model strings in config.toml from the openai-codex/ provider prefix to " +
605
+ "openai/ (comment-preserving and reversible — switching routes later just re-runs this step). Neither route has " +
606
+ "anything to do with memory embeddings: those run locally by default, and pi's key is never used for them.";
607
+
608
+ // ---- route decision ---------------------------------------------------------
609
+
610
+ export function parseRouteAnswer(answer: string): AuthRoute | null {
611
+ const a = answer.trim().toLowerCase();
612
+ if (["1", "oauth", "chatgpt", "subscription", "login"].includes(a)) return "oauth";
613
+ if (["2", "api", "key", "api key", "api-key", "apikey"].includes(a)) return "api";
614
+ return null;
615
+ }
616
+
617
+ /** The recorded route: the shared choice reader first, then this step's own
618
+ * record (an older checklist), read through the same reader. */
619
+ function recordedRoute(ctx: StepContext): AuthRoute | null {
620
+ return authRouteOf(ctx.choices) ?? authRouteOf({ [AUTH_ROUTE_CHOICE_KEY]: ctx.data.route });
621
+ }
622
+
623
+ interface RouteDecision {
624
+ route: AuthRoute | null;
625
+ source: string;
626
+ }
627
+
628
+ /**
629
+ * run() re-decides the route every time, so switching later is just "change the
630
+ * world and run the step again" — which is what makes the rewrite reversible in
631
+ * practice. Order:
632
+ * 1. the prompter (the non-LLM fallback entry actually asks the question);
633
+ * 2. otherwise the credential reality, using pi's OWN resolution order
634
+ * (CLI flag → auth.json → env): a completed host login means the OAuth
635
+ * route is what pi will really use, so the config must say so;
636
+ * 3. otherwise a valid key file;
637
+ * 4. otherwise the previously recorded route;
638
+ * 5. otherwise: no answer yet — the step goes red with the choice text.
639
+ */
640
+ async function decideRoute(
641
+ ctx: StepContext,
642
+ keyFile: KeyFileState,
643
+ hostLogin: boolean,
644
+ ): Promise<RouteDecision> {
645
+ const prompter = ctx.adapters.prompter;
646
+ if (prompter) {
647
+ const answer = await prompter(ROUTE_QUESTION);
648
+ const parsed = parseRouteAnswer(answer);
649
+ if (parsed) return { route: parsed, source: "you chose it" };
650
+ const kept = recordedRoute(ctx);
651
+ if (!answer.trim() && kept)
652
+ return { route: kept, source: "kept the recorded route (empty answer)" };
653
+ return { route: null, source: `did not understand the answer — reply 1/oauth or 2/api` };
654
+ }
655
+ if (hostLogin)
656
+ return {
657
+ route: "oauth",
658
+ source: "a completed pi login is on this host, and pi prefers auth.json over any env key",
659
+ };
660
+ if (keyFile.valid)
661
+ return { route: "api", source: `a valid ${OPENAI_KEY_FILE} is in the secrets dir` };
662
+ const kept = recordedRoute(ctx);
663
+ if (kept) return { route: kept, source: "the recorded route" };
664
+ return { route: null, source: "nothing on disk says which route this installation uses" };
665
+ }
666
+
667
+ // ---- config loading ---------------------------------------------------------
668
+
669
+ interface ConfigState {
670
+ path: string;
671
+ text: string | null;
672
+ /** Set when this call seeded config.toml from config.example.toml. */
673
+ seeded: boolean;
674
+ error: string | null;
675
+ }
676
+
677
+ function loadConfig(paths: OnboardAdapters["paths"], allowSeed: boolean): ConfigState {
678
+ const path = paths.configPath;
679
+ if (existsSync(path)) {
680
+ try {
681
+ return { path, text: readFileSync(path, "utf8"), seeded: false, error: null };
682
+ } catch (err) {
683
+ return { path, text: null, seeded: false, error: `cannot read ${path}: ${String(err)}` };
684
+ }
685
+ }
686
+ const example = configExamplePathFor(paths.stateDir);
687
+ if (!allowSeed)
688
+ return {
689
+ path,
690
+ text: null,
691
+ seeded: false,
692
+ error: `${path} does not exist yet — run this step to create it from config.example.toml`,
693
+ };
694
+ if (!existsSync(example))
695
+ return {
696
+ path,
697
+ text: null,
698
+ seeded: false,
699
+ error: `neither ${path} nor ${example} exists — is this a QuickReview checkout?`,
700
+ };
701
+ try {
702
+ // A fresh install's config lives in the config home, which may
703
+ // not exist yet.
704
+ mkdirSync(dirname(path), { recursive: true });
705
+ copyFileSync(example, path);
706
+ return { path, text: readFileSync(path, "utf8"), seeded: true, error: null };
707
+ } catch (err) {
708
+ return {
709
+ path,
710
+ text: null,
711
+ seeded: false,
712
+ error: `could not create ${path} from config.example.toml: ${String(err)}`,
713
+ };
714
+ }
715
+ }
716
+
717
+ // ---- checks -----------------------------------------------------------------
718
+
719
+ function embeddingsCheck(): CheckResult {
720
+ return { name: "embeddings", ok: true, detail: EMBEDDINGS_NOTE };
721
+ }
722
+
723
+ function modelsCheck(audit: ModelAudit[], route: AuthRoute, note: string): CheckResult {
724
+ const wrong = audit
725
+ .filter((a) => a.kind === "oauth" || a.kind === "api")
726
+ .filter((a) => a.kind !== route);
727
+ const missing = audit.filter((a) => a.kind === "missing");
728
+ const custom = audit.filter((a) => a.kind === "custom");
729
+ const tail = [
730
+ custom.length ? `left alone on another provider: ${custom.map((c) => c.label).join(", ")}` : "",
731
+ note,
732
+ ]
733
+ .filter(Boolean)
734
+ .join("; ");
735
+ if (wrong.length === 0 && missing.length === 0) {
736
+ return {
737
+ name: "models",
738
+ ok: true,
739
+ detail: `all ${audit.length - custom.length} model strings use the ${prefixFor(route)} prefix (${route} route)${tail ? ` — ${tail}` : ""}`,
740
+ };
741
+ }
742
+ const problems = [
743
+ wrong.length
744
+ ? `still on the wrong provider: ${wrong.map((w) => `${w.label}="${w.value}"`).join(", ")}`
745
+ : "",
746
+ missing.length ? `not found in config.toml: ${missing.map((m) => m.label).join(", ")}` : "",
747
+ ].filter(Boolean);
748
+ return {
749
+ name: "models",
750
+ ok: false,
751
+ detail: `${problems.join("; ")} — expected the ${prefixFor(route)} prefix for the ${route} route${tail ? ` (${tail})` : ""}`,
752
+ };
753
+ }
754
+
755
+ /**
756
+ * What the route means for the companion. Its container is never handed the
757
+ * API key file, so on the api route an `openai/` companion model has no
758
+ * credential, and the shipped `openai-codex/` one keeps needing the
759
+ * companion's own login.
760
+ */
761
+ function companionModelNote(configText: string, route: AuthRoute): string {
762
+ const model = readTomlString(configText, "companion", "model") ?? COMPANION_DEFAULTS.model;
763
+ if (route === "oauth") {
764
+ return model.startsWith(OAUTH_PREFIX)
765
+ ? ""
766
+ : `[companion] model is set to "${model}" — the companion is yours to point where you like, but on the oauth route it usually wants the ${OAUTH_PREFIX} prefix too`;
767
+ }
768
+ return model.startsWith(API_PREFIX)
769
+ ? `[companion] model is "${model}", but the companion container is never handed ${OPENAI_KEY_FILE}, so that model has no ` +
770
+ `credential there — point it at ${OAUTH_PREFIX} and log the companion in, or pass OPENAI_API_KEY to its container yourself`
771
+ : `the companion (model "${model}") is not covered by ${OPENAI_KEY_FILE} — its container is never handed the key, so it keeps ` +
772
+ "its own login (/login in its pi)";
773
+ }
774
+
775
+ async function companionLoginChecks(ctx: StepContext, configText: string): Promise<CheckResult[]> {
776
+ const model = readTomlString(configText, "companion", "model") ?? COMPANION_DEFAULTS.model;
777
+ if (!model.startsWith(OAUTH_PREFIX)) return [];
778
+ const name = companionContainerName(configText);
779
+ return [
780
+ loginCheck(
781
+ "companion_login",
782
+ "companion container",
783
+ { command: localAttach(name, companionSessionName(configText)), tmux: true },
784
+ await probeContainerLogin(ctx.adapters.runner, name),
785
+ ),
786
+ ];
787
+ }
788
+
789
+ async function oauthLoginChecks(
790
+ ctx: StepContext,
791
+ configText: string,
792
+ home: string,
793
+ ): Promise<CheckResult[]> {
794
+ const checks: CheckResult[] = [];
795
+ const authPath = hostAuthJsonPath(home);
796
+ const hostOk = hostHasOAuthLogin(authPath);
797
+ checks.push(
798
+ hostOk
799
+ ? {
800
+ name: "wizard_login",
801
+ ok: true,
802
+ detail: `this host's pi is logged in (${authPath}) — login 1 of 3 done`,
803
+ }
804
+ : {
805
+ name: "wizard_login",
806
+ ok: false,
807
+ detail:
808
+ `no ChatGPT (${OAUTH_PROVIDER}) OAuth login in this host's pi (${authPath}). Log in from this very session — type /login at pi's input line ` +
809
+ "and follow the browser flow — then run this step again. This is login 1 of 3; the two container logins come later.",
810
+ },
811
+ );
812
+ const runner = ctx.adapters.runner;
813
+ // The daemon runs where the topology says: on the VM route its container is
814
+ // on the review host, so the probe goes there over ssh (the transport's own
815
+ // facts: alias, container, sudo). The companion is always this machine's.
816
+ // The repair command names the same host and container the probe reached.
817
+ const vm = topologyOf(ctx.choices) === "vm";
818
+ let daemon = vm ? "" : await localDaemonContainer(runner, rootOf(ctx.adapters), configText);
819
+ let daemonRunner: ProcessRunner = runner;
820
+ let daemonAttach = daemonLoginCommand(daemon);
821
+ if (vm) {
822
+ const facts = remoteFactsFor(ctx.adapters, ctx.choices);
823
+ daemon = facts.container;
824
+ const prefix = facts.sudo ? ["sudo"] : [];
825
+ daemonAttach = `ssh -t ${facts.alias || "<vm>"} ${facts.sudo ? "sudo " : ""}${daemonLoginCommand(daemon)}`;
826
+ daemonRunner =
827
+ facts.alias === ""
828
+ ? { run: async () => ({ code: 1, stdout: "", stderr: "no ssh alias recorded" }) }
829
+ : {
830
+ run: (cmd, args) => runner.run("ssh", sshArgv(facts.alias, [...prefix, cmd, ...args])),
831
+ };
832
+ }
833
+ checks.push(
834
+ loginCheck(
835
+ "daemon_login",
836
+ "daemon container",
837
+ { command: daemonAttach, tmux: false },
838
+ await probeContainerLogin(daemonRunner, daemon),
839
+ ),
840
+ );
841
+ checks.push(...(await companionLoginChecks(ctx, configText)));
842
+ return checks;
843
+ }
844
+
845
+ // ---- the step ---------------------------------------------------------------
846
+
847
+ export function llmAuthStep(opts: { transport?: TransportOptions } = {}): OnboardingStep {
848
+ return {
849
+ id: LLM_AUTH_STEP_ID,
850
+ title: "LLM auth: ChatGPT OAuth or an API key",
851
+ explain: STEP_EXPLAIN,
852
+ // After preflight (10) and the topology question (20): the spec's second
853
+ // question, and everything after it assumes a decided route.
854
+ order: 30,
855
+
856
+ async run(ctx): Promise<StepReport> {
857
+ const home = hostHome();
858
+ const cfg = loadConfig(ctx.adapters.paths, true);
859
+ if (cfg.text === null) {
860
+ return {
861
+ ok: false,
862
+ checks: [{ name: "config", ok: false, detail: cfg.error ?? "config.toml unavailable" }],
863
+ };
864
+ }
865
+ const checks: CheckResult[] = [];
866
+ if (cfg.seeded) {
867
+ checks.push({
868
+ name: "config",
869
+ ok: true,
870
+ detail: `created ${cfg.path} from config.example.toml (its FILL values are untouched — later steps fill them)`,
871
+ });
872
+ }
873
+
874
+ const secretsDir = resolveSecretsDir(
875
+ cfg.text,
876
+ home,
877
+ process.env.QC_SECRETS_DIR,
878
+ rootOf(ctx.adapters),
879
+ );
880
+ let keyFile = readKeyFileState(secretsDir);
881
+ const hostLogin = hostHasOAuthLogin(hostAuthJsonPath(home));
882
+
883
+ const decision = await decideRoute(ctx, keyFile, hostLogin);
884
+ if (decision.route === null) {
885
+ checks.push({ name: "route", ok: false, detail: `${decision.source}.\n${ROUTE_QUESTION}` });
886
+ return { ok: false, checks };
887
+ }
888
+ const route = decision.route;
889
+ checks.push({ name: "route", ok: true, detail: `${route} route — ${decision.source}` });
890
+
891
+ let credentialChanged =
892
+ ctx.data.credentials_owed === true ||
893
+ (route === "api" &&
894
+ (recordedRoute(ctx) !== "api" ||
895
+ auditModelStrings(cfg.text).some((model) => model.kind === "oauth")));
896
+ // --- the credential ------------------------------------------------
897
+ if (route === "api") {
898
+ if (!keyFile.valid) {
899
+ const prompter = ctx.adapters.prompter;
900
+ if (prompter) {
901
+ const pasted = await prompter(KEY_QUESTION);
902
+ if (!pasted.trim()) {
903
+ checks.push({
904
+ name: "credential",
905
+ ok: false,
906
+ detail: `no key entered — nothing was written to ${keyFile.path}. Run this step again, or collect the key with: bash deploy/collect-secrets.sh`,
907
+ });
908
+ } else if (!validateOpenAiKey(pasted)) {
909
+ // The value itself is NEVER echoed back.
910
+ checks.push({
911
+ name: "credential",
912
+ ok: false,
913
+ detail:
914
+ "that does not look like an OpenAI API key (they start with sk- and contain no spaces) — nothing was written",
915
+ });
916
+ } else {
917
+ writeKeyFile(secretsDir, pasted);
918
+ credentialChanged = true;
919
+ keyFile = readKeyFileState(secretsDir);
920
+ checks.push({
921
+ name: "credential",
922
+ ok: true,
923
+ detail:
924
+ `saved to ${keyFile.path} (0600, dir 0700) — the daemon container's entrypoint exports it as OPENAI_API_KEY ` +
925
+ "for every review session; the companion container is never handed it (see the models note)",
926
+ });
927
+ }
928
+ } else {
929
+ checks.push({
930
+ name: "credential",
931
+ ok: false,
932
+ detail:
933
+ `no valid ${OPENAI_KEY_FILE} in ${secretsDir}. Collect it with the secrets wizard, in another terminal: ` +
934
+ "bash deploy/collect-secrets.sh — it reads the key with hidden input and writes it 0600. " +
935
+ "(The key never passes through this session or any command line.) Then run this step again.",
936
+ });
937
+ }
938
+ } else {
939
+ checks.push({
940
+ name: "credential",
941
+ ok: true,
942
+ detail: `${OPENAI_KEY_FILE} present in ${secretsDir} — the daemon container's entrypoint exports it for every review session`,
943
+ });
944
+ }
945
+ }
946
+
947
+ // A refused credential leaves the previously working models and the
948
+ // running daemon exactly as they were: nothing is rewritten or delivered.
949
+ if (checks.some((c) => c.name === "credential" && !c.ok)) {
950
+ return {
951
+ ok: false,
952
+ checks,
953
+ data: {
954
+ restart_owed: ctx.data.restart_owed === true,
955
+ credentials_owed: ctx.data.credentials_owed === true,
956
+ },
957
+ };
958
+ }
959
+
960
+ // --- the model strings ---------------------------------------------
961
+ const rewrite = rewriteModelPrefixes(cfg.text, route);
962
+ if (rewrite.text !== cfg.text) {
963
+ try {
964
+ writeAtomic(cfg.path, rewrite.text);
965
+ } catch (err) {
966
+ checks.push({
967
+ name: "models",
968
+ ok: false,
969
+ detail: `could not write ${cfg.path}: ${String(err)}`,
970
+ });
971
+ return { ok: false, checks };
972
+ }
973
+ }
974
+ const configText = rewrite.text;
975
+ const audit = auditModelStrings(configText);
976
+ const note = [
977
+ rewrite.rewritten.length
978
+ ? `rewrote ${rewrite.rewritten.length}: ${rewrite.rewritten.join(", ")}`
979
+ : "already on this route",
980
+ companionModelNote(configText, route),
981
+ ]
982
+ .filter(Boolean)
983
+ .join("; ");
984
+ checks.push(modelsCheck(audit, route, note));
985
+
986
+ // --- the logins ------------------------------------------------------
987
+ if (route === "oauth") checks.push(...(await oauthLoginChecks(ctx, configText, home)));
988
+ else checks.push(...(await companionLoginChecks(ctx, configText)));
989
+ const delivery = await deliverConfigChange(
990
+ ctx,
991
+ {
992
+ ...opts.transport,
993
+ ...(credentialChanged ? { deploymentMode: "provision" as const } : {}),
994
+ },
995
+ ctx.data.restart_owed === true || credentialChanged || rewrite.text !== cfg.text,
996
+ LLM_AUTH_STEP_ID,
997
+ );
998
+ checks.push(...delivery.checks);
999
+ checks.push(embeddingsCheck());
1000
+
1001
+ const ok = checks.every((c) => c.ok);
1002
+ if (ok) {
1003
+ ctx.recordChoice(CHOICE_KEYS.authRoute, route);
1004
+ ctx.recordChoice(MODEL_PREFIX_CHOICE_KEY, prefixFor(route));
1005
+ return {
1006
+ ok,
1007
+ checks,
1008
+ data: {
1009
+ route,
1010
+ prefix: prefixFor(route),
1011
+ config_path: cfg.path,
1012
+ models: modelLabels(),
1013
+ restart_owed: delivery.restartOwed,
1014
+ credentials_owed: credentialChanged && delivery.restartOwed,
1015
+ },
1016
+ };
1017
+ }
1018
+ return {
1019
+ ok,
1020
+ checks,
1021
+ data: {
1022
+ restart_owed: delivery.restartOwed,
1023
+ credentials_owed: credentialChanged && delivery.restartOwed,
1024
+ },
1025
+ };
1026
+ },
1027
+
1028
+ async verify(ctx): Promise<StepReport> {
1029
+ const owed = configDeliveryChecks(ctx);
1030
+ if (owed.length) return { ok: false, checks: owed };
1031
+ // Never prompts, never writes, never touches a credential value.
1032
+ const home = hostHome();
1033
+ const route = recordedRoute(ctx);
1034
+ if (route === null) {
1035
+ return {
1036
+ ok: false,
1037
+ checks: [
1038
+ {
1039
+ name: "route",
1040
+ ok: false,
1041
+ detail: "no LLM auth route recorded — run this step to choose one",
1042
+ },
1043
+ ],
1044
+ };
1045
+ }
1046
+ const cfg = loadConfig(ctx.adapters.paths, false);
1047
+ if (cfg.text === null) {
1048
+ return {
1049
+ ok: false,
1050
+ checks: [
1051
+ { name: "route", ok: true, detail: `${route} route recorded` },
1052
+ { name: "config", ok: false, detail: cfg.error ?? "config.toml unavailable" },
1053
+ ],
1054
+ };
1055
+ }
1056
+ const checks: CheckResult[] = [
1057
+ { name: "route", ok: true, detail: `${route} route recorded` },
1058
+ ];
1059
+ const secretsDir = resolveSecretsDir(
1060
+ cfg.text,
1061
+ home,
1062
+ process.env.QC_SECRETS_DIR,
1063
+ rootOf(ctx.adapters),
1064
+ );
1065
+ const keyFile = readKeyFileState(secretsDir);
1066
+
1067
+ if (route === "api") {
1068
+ checks.push(
1069
+ keyFile.valid
1070
+ ? {
1071
+ name: "credential",
1072
+ ok: true,
1073
+ detail: `${OPENAI_KEY_FILE} present in ${secretsDir}`,
1074
+ }
1075
+ : {
1076
+ name: "credential",
1077
+ ok: false,
1078
+ detail: keyFile.present
1079
+ ? `${keyFile.path} does not look like an OpenAI API key (they start with sk-) — re-run the step or bash deploy/collect-secrets.sh`
1080
+ : `the api route needs ${OPENAI_KEY_FILE} in ${secretsDir} — run bash deploy/collect-secrets.sh, or re-run this step to switch back to the OAuth route`,
1081
+ },
1082
+ );
1083
+ }
1084
+
1085
+ checks.push(
1086
+ modelsCheck(auditModelStrings(cfg.text), route, companionModelNote(cfg.text, route)),
1087
+ );
1088
+ if (route === "oauth") checks.push(...(await oauthLoginChecks(ctx, cfg.text, home)));
1089
+ else checks.push(...(await companionLoginChecks(ctx, cfg.text)));
1090
+ checks.push(embeddingsCheck());
1091
+
1092
+ return { ok: checks.every((c) => c.ok), checks };
1093
+ },
1094
+ };
1095
+ }