@apralabs/apra-fleet 0.2.2

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 (482) hide show
  1. package/LICENSE +182 -0
  2. package/README.md +324 -0
  3. package/dist/cli/auth.d.ts +2 -0
  4. package/dist/cli/auth.d.ts.map +1 -0
  5. package/dist/cli/auth.js +210 -0
  6. package/dist/cli/auth.js.map +1 -0
  7. package/dist/cli/config.d.ts +30 -0
  8. package/dist/cli/config.d.ts.map +1 -0
  9. package/dist/cli/config.js +157 -0
  10. package/dist/cli/config.js.map +1 -0
  11. package/dist/cli/install.d.ts +37 -0
  12. package/dist/cli/install.d.ts.map +1 -0
  13. package/dist/cli/install.js +630 -0
  14. package/dist/cli/install.js.map +1 -0
  15. package/dist/cli/secret.d.ts +2 -0
  16. package/dist/cli/secret.d.ts.map +1 -0
  17. package/dist/cli/secret.js +366 -0
  18. package/dist/cli/secret.js.map +1 -0
  19. package/dist/cli/uninstall.d.ts +2 -0
  20. package/dist/cli/uninstall.d.ts.map +1 -0
  21. package/dist/cli/uninstall.js +312 -0
  22. package/dist/cli/uninstall.js.map +1 -0
  23. package/dist/cli/update.d.ts +2 -0
  24. package/dist/cli/update.d.ts.map +1 -0
  25. package/dist/cli/update.js +105 -0
  26. package/dist/cli/update.js.map +1 -0
  27. package/dist/delivery-mode.d.ts +19 -0
  28. package/dist/delivery-mode.d.ts.map +1 -0
  29. package/dist/delivery-mode.js +26 -0
  30. package/dist/delivery-mode.js.map +1 -0
  31. package/dist/index.d.ts +3 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +272 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/onboarding/text.d.ts +83 -0
  36. package/dist/onboarding/text.d.ts.map +1 -0
  37. package/dist/onboarding/text.js +126 -0
  38. package/dist/onboarding/text.js.map +1 -0
  39. package/dist/os/index.d.ts +9 -0
  40. package/dist/os/index.d.ts.map +1 -0
  41. package/dist/os/index.js +16 -0
  42. package/dist/os/index.js.map +1 -0
  43. package/dist/os/linux.d.ts +50 -0
  44. package/dist/os/linux.d.ts.map +1 -0
  45. package/dist/os/linux.js +244 -0
  46. package/dist/os/linux.js.map +1 -0
  47. package/dist/os/macos.d.ts +12 -0
  48. package/dist/os/macos.d.ts.map +1 -0
  49. package/dist/os/macos.js +41 -0
  50. package/dist/os/macos.js.map +1 -0
  51. package/dist/os/os-commands.d.ts +47 -0
  52. package/dist/os/os-commands.d.ts.map +1 -0
  53. package/dist/os/os-commands.js +3 -0
  54. package/dist/os/os-commands.js.map +1 -0
  55. package/dist/os/windows-wrapper.d.ts +6 -0
  56. package/dist/os/windows-wrapper.d.ts.map +1 -0
  57. package/dist/os/windows-wrapper.js +9 -0
  58. package/dist/os/windows-wrapper.js.map +1 -0
  59. package/dist/os/windows.d.ts +44 -0
  60. package/dist/os/windows.d.ts.map +1 -0
  61. package/dist/os/windows.js +269 -0
  62. package/dist/os/windows.js.map +1 -0
  63. package/dist/paths.d.ts +2 -0
  64. package/dist/paths.d.ts.map +1 -0
  65. package/dist/paths.js +4 -0
  66. package/dist/paths.js.map +1 -0
  67. package/dist/providers/agy.d.ts +41 -0
  68. package/dist/providers/agy.d.ts.map +1 -0
  69. package/dist/providers/agy.js +208 -0
  70. package/dist/providers/agy.js.map +1 -0
  71. package/dist/providers/claude.d.ts +40 -0
  72. package/dist/providers/claude.d.ts.map +1 -0
  73. package/dist/providers/claude.js +178 -0
  74. package/dist/providers/claude.js.map +1 -0
  75. package/dist/providers/codex.d.ts +44 -0
  76. package/dist/providers/codex.d.ts.map +1 -0
  77. package/dist/providers/codex.js +173 -0
  78. package/dist/providers/codex.js.map +1 -0
  79. package/dist/providers/copilot.d.ts +40 -0
  80. package/dist/providers/copilot.d.ts.map +1 -0
  81. package/dist/providers/copilot.js +172 -0
  82. package/dist/providers/copilot.js.map +1 -0
  83. package/dist/providers/gemini.d.ts +41 -0
  84. package/dist/providers/gemini.d.ts.map +1 -0
  85. package/dist/providers/gemini.js +192 -0
  86. package/dist/providers/gemini.js.map +1 -0
  87. package/dist/providers/index.d.ts +10 -0
  88. package/dist/providers/index.d.ts.map +1 -0
  89. package/dist/providers/index.js +27 -0
  90. package/dist/providers/index.js.map +1 -0
  91. package/dist/providers/provider.d.ts +85 -0
  92. package/dist/providers/provider.d.ts.map +1 -0
  93. package/dist/providers/provider.js +21 -0
  94. package/dist/providers/provider.js.map +1 -0
  95. package/dist/services/auth-socket.d.ts +87 -0
  96. package/dist/services/auth-socket.d.ts.map +1 -0
  97. package/dist/services/auth-socket.js +684 -0
  98. package/dist/services/auth-socket.js.map +1 -0
  99. package/dist/services/auth-web.d.ts +31 -0
  100. package/dist/services/auth-web.d.ts.map +1 -0
  101. package/dist/services/auth-web.js +202 -0
  102. package/dist/services/auth-web.js.map +1 -0
  103. package/dist/services/cloud/activity.d.ts +16 -0
  104. package/dist/services/cloud/activity.d.ts.map +1 -0
  105. package/dist/services/cloud/activity.js +61 -0
  106. package/dist/services/cloud/activity.js.map +1 -0
  107. package/dist/services/cloud/aws.d.ts +24 -0
  108. package/dist/services/cloud/aws.d.ts.map +1 -0
  109. package/dist/services/cloud/aws.js +114 -0
  110. package/dist/services/cloud/aws.js.map +1 -0
  111. package/dist/services/cloud/cost.d.ts +46 -0
  112. package/dist/services/cloud/cost.d.ts.map +1 -0
  113. package/dist/services/cloud/cost.js +161 -0
  114. package/dist/services/cloud/cost.js.map +1 -0
  115. package/dist/services/cloud/idle-manager.d.ts +20 -0
  116. package/dist/services/cloud/idle-manager.d.ts.map +1 -0
  117. package/dist/services/cloud/idle-manager.js +103 -0
  118. package/dist/services/cloud/idle-manager.js.map +1 -0
  119. package/dist/services/cloud/lifecycle.d.ts +14 -0
  120. package/dist/services/cloud/lifecycle.d.ts.map +1 -0
  121. package/dist/services/cloud/lifecycle.js +128 -0
  122. package/dist/services/cloud/lifecycle.js.map +1 -0
  123. package/dist/services/cloud/task-wrapper.d.ts +30 -0
  124. package/dist/services/cloud/task-wrapper.d.ts.map +1 -0
  125. package/dist/services/cloud/task-wrapper.js +116 -0
  126. package/dist/services/cloud/task-wrapper.js.map +1 -0
  127. package/dist/services/cloud/types.d.ts +26 -0
  128. package/dist/services/cloud/types.d.ts.map +1 -0
  129. package/dist/services/cloud/types.js +2 -0
  130. package/dist/services/cloud/types.js.map +1 -0
  131. package/dist/services/credential-cleanup.d.ts +4 -0
  132. package/dist/services/credential-cleanup.d.ts.map +1 -0
  133. package/dist/services/credential-cleanup.js +61 -0
  134. package/dist/services/credential-cleanup.js.map +1 -0
  135. package/dist/services/credential-store.d.ts +56 -0
  136. package/dist/services/credential-store.d.ts.map +1 -0
  137. package/dist/services/credential-store.js +280 -0
  138. package/dist/services/credential-store.js.map +1 -0
  139. package/dist/services/file-transfer.d.ts +22 -0
  140. package/dist/services/file-transfer.d.ts.map +1 -0
  141. package/dist/services/file-transfer.js +14 -0
  142. package/dist/services/file-transfer.js.map +1 -0
  143. package/dist/services/git-config.d.ts +6 -0
  144. package/dist/services/git-config.d.ts.map +1 -0
  145. package/dist/services/git-config.js +31 -0
  146. package/dist/services/git-config.js.map +1 -0
  147. package/dist/services/github-app.d.ts +30 -0
  148. package/dist/services/github-app.d.ts.map +1 -0
  149. package/dist/services/github-app.js +96 -0
  150. package/dist/services/github-app.js.map +1 -0
  151. package/dist/services/icons.d.ts +16 -0
  152. package/dist/services/icons.d.ts.map +1 -0
  153. package/dist/services/icons.js +67 -0
  154. package/dist/services/icons.js.map +1 -0
  155. package/dist/services/known-hosts.d.ts +23 -0
  156. package/dist/services/known-hosts.d.ts.map +1 -0
  157. package/dist/services/known-hosts.js +86 -0
  158. package/dist/services/known-hosts.js.map +1 -0
  159. package/dist/services/onboarding.d.ts +68 -0
  160. package/dist/services/onboarding.d.ts.map +1 -0
  161. package/dist/services/onboarding.js +205 -0
  162. package/dist/services/onboarding.js.map +1 -0
  163. package/dist/services/registry.d.ts +16 -0
  164. package/dist/services/registry.d.ts.map +1 -0
  165. package/dist/services/registry.js +156 -0
  166. package/dist/services/registry.js.map +1 -0
  167. package/dist/services/sftp.d.ts +16 -0
  168. package/dist/services/sftp.d.ts.map +1 -0
  169. package/dist/services/sftp.js +104 -0
  170. package/dist/services/sftp.js.map +1 -0
  171. package/dist/services/ssh.d.ts +29 -0
  172. package/dist/services/ssh.d.ts.map +1 -0
  173. package/dist/services/ssh.js +297 -0
  174. package/dist/services/ssh.js.map +1 -0
  175. package/dist/services/stall/find-log-file.d.ts +2 -0
  176. package/dist/services/stall/find-log-file.d.ts.map +1 -0
  177. package/dist/services/stall/find-log-file.js +153 -0
  178. package/dist/services/stall/find-log-file.js.map +1 -0
  179. package/dist/services/stall/index.d.ts +4 -0
  180. package/dist/services/stall/index.d.ts.map +1 -0
  181. package/dist/services/stall/index.js +4 -0
  182. package/dist/services/stall/index.js.map +1 -0
  183. package/dist/services/stall/log-path-resolver.d.ts +4 -0
  184. package/dist/services/stall/log-path-resolver.d.ts.map +1 -0
  185. package/dist/services/stall/log-path-resolver.js +32 -0
  186. package/dist/services/stall/log-path-resolver.js.map +1 -0
  187. package/dist/services/stall/log-path-resolver.test.d.ts +2 -0
  188. package/dist/services/stall/log-path-resolver.test.d.ts.map +1 -0
  189. package/dist/services/stall/log-path-resolver.test.js +76 -0
  190. package/dist/services/stall/log-path-resolver.test.js.map +1 -0
  191. package/dist/services/stall/read-log-tail.d.ts +6 -0
  192. package/dist/services/stall/read-log-tail.d.ts.map +1 -0
  193. package/dist/services/stall/read-log-tail.js +44 -0
  194. package/dist/services/stall/read-log-tail.js.map +1 -0
  195. package/dist/services/stall/stall-detector.d.ts +25 -0
  196. package/dist/services/stall/stall-detector.d.ts.map +1 -0
  197. package/dist/services/stall/stall-detector.js +153 -0
  198. package/dist/services/stall/stall-detector.js.map +1 -0
  199. package/dist/services/stall/stall-poller.d.ts +6 -0
  200. package/dist/services/stall/stall-poller.d.ts.map +1 -0
  201. package/dist/services/stall/stall-poller.js +75 -0
  202. package/dist/services/stall/stall-poller.js.map +1 -0
  203. package/dist/services/stall/time-utils.d.ts +4 -0
  204. package/dist/services/stall/time-utils.d.ts.map +1 -0
  205. package/dist/services/stall/time-utils.js +22 -0
  206. package/dist/services/stall/time-utils.js.map +1 -0
  207. package/dist/services/statusline.d.ts +10 -0
  208. package/dist/services/statusline.d.ts.map +1 -0
  209. package/dist/services/statusline.js +84 -0
  210. package/dist/services/statusline.js.map +1 -0
  211. package/dist/services/strategy.d.ts +16 -0
  212. package/dist/services/strategy.d.ts.map +1 -0
  213. package/dist/services/strategy.js +241 -0
  214. package/dist/services/strategy.js.map +1 -0
  215. package/dist/services/task-cleanup.d.ts +3 -0
  216. package/dist/services/task-cleanup.d.ts.map +1 -0
  217. package/dist/services/task-cleanup.js +81 -0
  218. package/dist/services/task-cleanup.js.map +1 -0
  219. package/dist/services/update-check.d.ts +15 -0
  220. package/dist/services/update-check.d.ts.map +1 -0
  221. package/dist/services/update-check.js +67 -0
  222. package/dist/services/update-check.js.map +1 -0
  223. package/dist/services/user-config.d.ts +12 -0
  224. package/dist/services/user-config.d.ts.map +1 -0
  225. package/dist/services/user-config.js +73 -0
  226. package/dist/services/user-config.js.map +1 -0
  227. package/dist/services/vcs/azure-devops.d.ts +7 -0
  228. package/dist/services/vcs/azure-devops.d.ts.map +1 -0
  229. package/dist/services/vcs/azure-devops.js +38 -0
  230. package/dist/services/vcs/azure-devops.js.map +1 -0
  231. package/dist/services/vcs/bitbucket.d.ts +6 -0
  232. package/dist/services/vcs/bitbucket.d.ts.map +1 -0
  233. package/dist/services/vcs/bitbucket.js +31 -0
  234. package/dist/services/vcs/bitbucket.js.map +1 -0
  235. package/dist/services/vcs/constants.d.ts +2 -0
  236. package/dist/services/vcs/constants.d.ts.map +1 -0
  237. package/dist/services/vcs/constants.js +6 -0
  238. package/dist/services/vcs/constants.js.map +1 -0
  239. package/dist/services/vcs/github.d.ts +6 -0
  240. package/dist/services/vcs/github.d.ts.map +1 -0
  241. package/dist/services/vcs/github.js +81 -0
  242. package/dist/services/vcs/github.js.map +1 -0
  243. package/dist/services/vcs/types.d.ts +52 -0
  244. package/dist/services/vcs/types.d.ts.map +1 -0
  245. package/dist/services/vcs/types.js +8 -0
  246. package/dist/services/vcs/types.js.map +1 -0
  247. package/dist/smoke-test.d.ts +10 -0
  248. package/dist/smoke-test.d.ts.map +1 -0
  249. package/dist/smoke-test.js +102 -0
  250. package/dist/smoke-test.js.map +1 -0
  251. package/dist/tools/check-status.d.ts +11 -0
  252. package/dist/tools/check-status.d.ts.map +1 -0
  253. package/dist/tools/check-status.js +247 -0
  254. package/dist/tools/check-status.js.map +1 -0
  255. package/dist/tools/cloud-control.d.ts +17 -0
  256. package/dist/tools/cloud-control.d.ts.map +1 -0
  257. package/dist/tools/cloud-control.js +102 -0
  258. package/dist/tools/cloud-control.js.map +1 -0
  259. package/dist/tools/compose-permissions.d.ts +26 -0
  260. package/dist/tools/compose-permissions.d.ts.map +1 -0
  261. package/dist/tools/compose-permissions.js +217 -0
  262. package/dist/tools/compose-permissions.js.map +1 -0
  263. package/dist/tools/credential-store-delete.d.ts +11 -0
  264. package/dist/tools/credential-store-delete.d.ts.map +1 -0
  265. package/dist/tools/credential-store-delete.js +15 -0
  266. package/dist/tools/credential-store-delete.js.map +1 -0
  267. package/dist/tools/credential-store-list.d.ts +4 -0
  268. package/dist/tools/credential-store-list.d.ts.map +1 -0
  269. package/dist/tools/credential-store-list.js +30 -0
  270. package/dist/tools/credential-store-list.js.map +1 -0
  271. package/dist/tools/credential-store-set.d.ts +26 -0
  272. package/dist/tools/credential-store-set.d.ts.map +1 -0
  273. package/dist/tools/credential-store-set.js +28 -0
  274. package/dist/tools/credential-store-set.js.map +1 -0
  275. package/dist/tools/credential-store-update.d.ts +20 -0
  276. package/dist/tools/credential-store-update.d.ts.map +1 -0
  277. package/dist/tools/credential-store-update.js +38 -0
  278. package/dist/tools/credential-store-update.js.map +1 -0
  279. package/dist/tools/execute-command.d.ts +33 -0
  280. package/dist/tools/execute-command.d.ts.map +1 -0
  281. package/dist/tools/execute-command.js +231 -0
  282. package/dist/tools/execute-command.js.map +1 -0
  283. package/dist/tools/execute-prompt.d.ts +36 -0
  284. package/dist/tools/execute-prompt.d.ts.map +1 -0
  285. package/dist/tools/execute-prompt.js +310 -0
  286. package/dist/tools/execute-prompt.js.map +1 -0
  287. package/dist/tools/list-members.d.ts +11 -0
  288. package/dist/tools/list-members.d.ts.map +1 -0
  289. package/dist/tools/list-members.js +108 -0
  290. package/dist/tools/list-members.js.map +1 -0
  291. package/dist/tools/member-detail.d.ts +17 -0
  292. package/dist/tools/member-detail.d.ts.map +1 -0
  293. package/dist/tools/member-detail.js +263 -0
  294. package/dist/tools/member-detail.js.map +1 -0
  295. package/dist/tools/monitor-task.d.ts +20 -0
  296. package/dist/tools/monitor-task.d.ts.map +1 -0
  297. package/dist/tools/monitor-task.js +89 -0
  298. package/dist/tools/monitor-task.js.map +1 -0
  299. package/dist/tools/provision-auth.d.ts +17 -0
  300. package/dist/tools/provision-auth.d.ts.map +1 -0
  301. package/dist/tools/provision-auth.js +256 -0
  302. package/dist/tools/provision-auth.js.map +1 -0
  303. package/dist/tools/provision-vcs-auth.d.ts +50 -0
  304. package/dist/tools/provision-vcs-auth.d.ts.map +1 -0
  305. package/dist/tools/provision-vcs-auth.js +187 -0
  306. package/dist/tools/provision-vcs-auth.js.map +1 -0
  307. package/dist/tools/receive-files.d.ts +20 -0
  308. package/dist/tools/receive-files.d.ts.map +1 -0
  309. package/dist/tools/receive-files.js +82 -0
  310. package/dist/tools/receive-files.js.map +1 -0
  311. package/dist/tools/register-member.d.ts +74 -0
  312. package/dist/tools/register-member.d.ts.map +1 -0
  313. package/dist/tools/register-member.js +310 -0
  314. package/dist/tools/register-member.js.map +1 -0
  315. package/dist/tools/remove-member.d.ts +17 -0
  316. package/dist/tools/remove-member.d.ts.map +1 -0
  317. package/dist/tools/remove-member.js +126 -0
  318. package/dist/tools/remove-member.js.map +1 -0
  319. package/dist/tools/revoke-vcs-auth.d.ts +23 -0
  320. package/dist/tools/revoke-vcs-auth.d.ts.map +1 -0
  321. package/dist/tools/revoke-vcs-auth.js +55 -0
  322. package/dist/tools/revoke-vcs-auth.js.map +1 -0
  323. package/dist/tools/send-files.d.ts +20 -0
  324. package/dist/tools/send-files.d.ts.map +1 -0
  325. package/dist/tools/send-files.js +103 -0
  326. package/dist/tools/send-files.js.map +1 -0
  327. package/dist/tools/setup-git-app.d.ts +17 -0
  328. package/dist/tools/setup-git-app.d.ts.map +1 -0
  329. package/dist/tools/setup-git-app.js +89 -0
  330. package/dist/tools/setup-git-app.js.map +1 -0
  331. package/dist/tools/setup-ssh-key.d.ts +14 -0
  332. package/dist/tools/setup-ssh-key.d.ts.map +1 -0
  333. package/dist/tools/setup-ssh-key.js +119 -0
  334. package/dist/tools/setup-ssh-key.js.map +1 -0
  335. package/dist/tools/shutdown-server.d.ts +4 -0
  336. package/dist/tools/shutdown-server.d.ts.map +1 -0
  337. package/dist/tools/shutdown-server.js +9 -0
  338. package/dist/tools/shutdown-server.js.map +1 -0
  339. package/dist/tools/stop-prompt.d.ts +14 -0
  340. package/dist/tools/stop-prompt.d.ts.map +1 -0
  341. package/dist/tools/stop-prompt.js +44 -0
  342. package/dist/tools/stop-prompt.js.map +1 -0
  343. package/dist/tools/update-agent-cli.d.ts +17 -0
  344. package/dist/tools/update-agent-cli.d.ts.map +1 -0
  345. package/dist/tools/update-agent-cli.js +110 -0
  346. package/dist/tools/update-agent-cli.js.map +1 -0
  347. package/dist/tools/update-member.d.ts +77 -0
  348. package/dist/tools/update-member.d.ts.map +1 -0
  349. package/dist/tools/update-member.js +202 -0
  350. package/dist/tools/update-member.js.map +1 -0
  351. package/dist/tools/version.d.ts +4 -0
  352. package/dist/tools/version.d.ts.map +1 -0
  353. package/dist/tools/version.js +7 -0
  354. package/dist/tools/version.js.map +1 -0
  355. package/dist/types.d.ts +70 -0
  356. package/dist/types.d.ts.map +1 -0
  357. package/dist/types.js +2 -0
  358. package/dist/types.js.map +1 -0
  359. package/dist/utils/agent-helpers.d.ts +41 -0
  360. package/dist/utils/agent-helpers.d.ts.map +1 -0
  361. package/dist/utils/agent-helpers.js +84 -0
  362. package/dist/utils/agent-helpers.js.map +1 -0
  363. package/dist/utils/ansi.d.ts +6 -0
  364. package/dist/utils/ansi.d.ts.map +1 -0
  365. package/dist/utils/ansi.js +20 -0
  366. package/dist/utils/ansi.js.map +1 -0
  367. package/dist/utils/auth-env.d.ts +8 -0
  368. package/dist/utils/auth-env.d.ts.map +1 -0
  369. package/dist/utils/auth-env.js +30 -0
  370. package/dist/utils/auth-env.js.map +1 -0
  371. package/dist/utils/collect-secret.d.ts +2 -0
  372. package/dist/utils/collect-secret.d.ts.map +1 -0
  373. package/dist/utils/collect-secret.js +80 -0
  374. package/dist/utils/collect-secret.js.map +1 -0
  375. package/dist/utils/credential-validation.d.ts +13 -0
  376. package/dist/utils/credential-validation.d.ts.map +1 -0
  377. package/dist/utils/credential-validation.js +35 -0
  378. package/dist/utils/credential-validation.js.map +1 -0
  379. package/dist/utils/crypto.d.ts +3 -0
  380. package/dist/utils/crypto.d.ts.map +1 -0
  381. package/dist/utils/crypto.js +61 -0
  382. package/dist/utils/crypto.js.map +1 -0
  383. package/dist/utils/deep-merge.d.ts +3 -0
  384. package/dist/utils/deep-merge.d.ts.map +1 -0
  385. package/dist/utils/deep-merge.js +23 -0
  386. package/dist/utils/deep-merge.js.map +1 -0
  387. package/dist/utils/file-permissions.d.ts +8 -0
  388. package/dist/utils/file-permissions.d.ts.map +1 -0
  389. package/dist/utils/file-permissions.js +13 -0
  390. package/dist/utils/file-permissions.js.map +1 -0
  391. package/dist/utils/gpu-parser.d.ts +6 -0
  392. package/dist/utils/gpu-parser.d.ts.map +1 -0
  393. package/dist/utils/gpu-parser.js +15 -0
  394. package/dist/utils/gpu-parser.js.map +1 -0
  395. package/dist/utils/log-helpers.d.ts +29 -0
  396. package/dist/utils/log-helpers.d.ts.map +1 -0
  397. package/dist/utils/log-helpers.js +128 -0
  398. package/dist/utils/log-helpers.js.map +1 -0
  399. package/dist/utils/oob-timeout.d.ts +2 -0
  400. package/dist/utils/oob-timeout.d.ts.map +1 -0
  401. package/dist/utils/oob-timeout.js +2 -0
  402. package/dist/utils/oob-timeout.js.map +1 -0
  403. package/dist/utils/pid-helpers.d.ts +11 -0
  404. package/dist/utils/pid-helpers.d.ts.map +1 -0
  405. package/dist/utils/pid-helpers.js +21 -0
  406. package/dist/utils/pid-helpers.js.map +1 -0
  407. package/dist/utils/platform.d.ts +13 -0
  408. package/dist/utils/platform.d.ts.map +1 -0
  409. package/dist/utils/platform.js +60 -0
  410. package/dist/utils/platform.js.map +1 -0
  411. package/dist/utils/prompt-errors.d.ts +5 -0
  412. package/dist/utils/prompt-errors.d.ts.map +1 -0
  413. package/dist/utils/prompt-errors.js +15 -0
  414. package/dist/utils/prompt-errors.js.map +1 -0
  415. package/dist/utils/resolve-member.d.ts +18 -0
  416. package/dist/utils/resolve-member.d.ts.map +1 -0
  417. package/dist/utils/resolve-member.js +23 -0
  418. package/dist/utils/resolve-member.js.map +1 -0
  419. package/dist/utils/secure-input.d.ts +6 -0
  420. package/dist/utils/secure-input.d.ts.map +1 -0
  421. package/dist/utils/secure-input.js +60 -0
  422. package/dist/utils/secure-input.js.map +1 -0
  423. package/dist/utils/shell-escape.d.ts +43 -0
  424. package/dist/utils/shell-escape.d.ts.map +1 -0
  425. package/dist/utils/shell-escape.js +67 -0
  426. package/dist/utils/shell-escape.js.map +1 -0
  427. package/dist/utils/ssh-error-messages.d.ts +5 -0
  428. package/dist/utils/ssh-error-messages.d.ts.map +1 -0
  429. package/dist/utils/ssh-error-messages.js +20 -0
  430. package/dist/utils/ssh-error-messages.js.map +1 -0
  431. package/dist/version.d.ts +18 -0
  432. package/dist/version.d.ts.map +1 -0
  433. package/dist/version.js +101 -0
  434. package/dist/version.js.map +1 -0
  435. package/hooks/hooks-config.json +15 -0
  436. package/hooks/post-register-member.sh +10 -0
  437. package/package.json +82 -0
  438. package/scripts/agy-settings-merge.js +27 -0
  439. package/scripts/agy-transcript-reader.js +62 -0
  440. package/scripts/fleet-statusline.sh +43 -0
  441. package/skills/fleet/SKILL.md +262 -0
  442. package/skills/fleet/auth-azdevops.md +72 -0
  443. package/skills/fleet/auth-bitbucket.md +65 -0
  444. package/skills/fleet/auth-github.md +86 -0
  445. package/skills/fleet/beads.md +90 -0
  446. package/skills/fleet/onboarding.md +92 -0
  447. package/skills/fleet/permissions.md +23 -0
  448. package/skills/fleet/profiles/base-dev.json +18 -0
  449. package/skills/fleet/profiles/base-reviewer.json +14 -0
  450. package/skills/fleet/profiles/cpp.json +4 -0
  451. package/skills/fleet/profiles/dotnet.json +4 -0
  452. package/skills/fleet/profiles/go.json +4 -0
  453. package/skills/fleet/profiles/jvm.json +4 -0
  454. package/skills/fleet/profiles/node.json +4 -0
  455. package/skills/fleet/profiles/python.json +4 -0
  456. package/skills/fleet/profiles/rust.json +4 -0
  457. package/skills/fleet/profiles/tpl-permissions.json +5 -0
  458. package/skills/fleet/skill-matrix.md +34 -0
  459. package/skills/fleet/troubleshooting.md +13 -0
  460. package/skills/pm/SKILL.md +110 -0
  461. package/skills/pm/backlog-item.md +65 -0
  462. package/skills/pm/beads.md +192 -0
  463. package/skills/pm/cleanup.md +15 -0
  464. package/skills/pm/context-file.md +40 -0
  465. package/skills/pm/doer-reviewer.md +123 -0
  466. package/skills/pm/init.md +25 -0
  467. package/skills/pm/multi-pair-sprint.md +64 -0
  468. package/skills/pm/plan-prompt.md +94 -0
  469. package/skills/pm/simple-sprint.md +42 -0
  470. package/skills/pm/single-pair-sprint.md +178 -0
  471. package/skills/pm/tpl-deploy.md +24 -0
  472. package/skills/pm/tpl-design.md +29 -0
  473. package/skills/pm/tpl-doer.md +43 -0
  474. package/skills/pm/tpl-plan.md +72 -0
  475. package/skills/pm/tpl-pm.md +2 -0
  476. package/skills/pm/tpl-progress.json +28 -0
  477. package/skills/pm/tpl-projects.md +4 -0
  478. package/skills/pm/tpl-requirements.md +21 -0
  479. package/skills/pm/tpl-reviewer-plan.md +53 -0
  480. package/skills/pm/tpl-reviewer.md +72 -0
  481. package/skills/pm/tpl-status.md +29 -0
  482. package/version.json +3 -0
@@ -0,0 +1,684 @@
1
+ import net from 'node:net';
2
+ import fs from 'node:fs';
3
+ import { promises as fsPromises } from 'node:fs';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import { spawn, execSync } from 'node:child_process';
7
+ import { FLEET_DIR } from '../paths.js';
8
+ import { encryptPassword } from '../utils/crypto.js';
9
+ import { logError } from '../utils/log-helpers.js';
10
+ import { OOB_TIMEOUT_MS } from '../utils/oob-timeout.js';
11
+ import { launchAuthWeb } from './auth-web.js';
12
+ const SOCKET_PATH = path.join(FLEET_DIR, 'auth.sock');
13
+ const PENDING_TTL_MS = 10 * 60 * 1000; // 10 minutes
14
+ const MAX_BUFFER_SIZE = 64 * 1024; // 64KB — reject oversized messages
15
+ const pendingRequests = new Map();
16
+ const passwordWaiters = new Map();
17
+ const activeSockets = new Set();
18
+ let socketServer = null;
19
+ let closingPromise = null;
20
+ let testPipeGeneration = 0;
21
+ export function getSocketPath() {
22
+ if (process.platform === 'win32') {
23
+ // Note: this path is automatically scoped to the user session by Windows.
24
+ const username = process.env.USERNAME ?? 'user';
25
+ const suffix = process.env.NODE_ENV === 'test' ? `-${testPipeGeneration}` : '';
26
+ return `\\\\.\\pipe\\apra-fleet-auth-${username}${suffix}`;
27
+ }
28
+ return SOCKET_PATH;
29
+ }
30
+ function killProcess(pid) {
31
+ if (!pid)
32
+ return;
33
+ try {
34
+ if (process.platform === 'win32') {
35
+ execSync(`taskkill /F /PID ${pid}`, { stdio: 'ignore' });
36
+ }
37
+ else {
38
+ process.kill(pid, 'SIGTERM');
39
+ }
40
+ }
41
+ catch {
42
+ // Process may have already exited
43
+ }
44
+ }
45
+ export async function ensureAuthSocket() {
46
+ // If already closing, wait for it to finish before trying to start again
47
+ if (closingPromise) {
48
+ await closingPromise;
49
+ }
50
+ if (socketServer)
51
+ return;
52
+ const sockPath = getSocketPath();
53
+ // Ensure parent directory exists
54
+ const sockDir = path.dirname(sockPath);
55
+ if (!fs.existsSync(sockDir)) {
56
+ fs.mkdirSync(sockDir, { recursive: true, mode: 0o700 });
57
+ }
58
+ // Unlink stale socket (Unix only — named pipes don't leave stale files)
59
+ if (process.platform !== 'win32') {
60
+ try {
61
+ fs.unlinkSync(sockPath);
62
+ }
63
+ catch { /* not present */ }
64
+ }
65
+ const tryListen = (retriesLeft) => new Promise((resolve, reject) => {
66
+ const server = net.createServer((conn) => {
67
+ activeSockets.add(conn);
68
+ conn.on('close', () => activeSockets.delete(conn));
69
+ let buffer = '';
70
+ conn.on('data', (chunk) => {
71
+ buffer += chunk.toString();
72
+ if (buffer.length > MAX_BUFFER_SIZE) {
73
+ conn.write(JSON.stringify({ type: 'ack', ok: false, error: 'Message too large' }) + '\n');
74
+ conn.end();
75
+ return;
76
+ }
77
+ const newlineIdx = buffer.indexOf('\n');
78
+ if (newlineIdx === -1)
79
+ return;
80
+ const line = buffer.slice(0, newlineIdx);
81
+ buffer = buffer.slice(newlineIdx + 1);
82
+ try {
83
+ const msg = JSON.parse(line);
84
+ if (msg.type === 'auth' && msg.member_name && msg.password) {
85
+ const res = submitPassword(msg.member_name, msg.password, msg.persist);
86
+ // Best-effort: JS strings are immutable; original may persist in V8 heap until GC
87
+ msg.password = '';
88
+ conn.write(JSON.stringify({ type: 'ack', ...res }) + '\n');
89
+ }
90
+ else {
91
+ conn.write(JSON.stringify({ type: 'ack', ok: false, error: 'Invalid message' }) + '\n');
92
+ }
93
+ }
94
+ catch {
95
+ conn.write(JSON.stringify({ type: 'ack', ok: false, error: 'Invalid JSON' }) + '\n');
96
+ }
97
+ });
98
+ });
99
+ server.on('error', (err) => {
100
+ server.close();
101
+ // On Windows, named pipes may not be released immediately after close.
102
+ // Retry a few times with increasing delays before giving up.
103
+ if (err.code === 'EADDRINUSE' && process.platform === 'win32' && retriesLeft > 0) {
104
+ // Increase delay for later retries — earlier retries happen faster
105
+ const totalRetries = process.env.NODE_ENV === 'test' ? 15 : 5;
106
+ const delayBase = process.env.NODE_ENV === 'test' ? 100 : 250;
107
+ const delay = delayBase * (totalRetries - retriesLeft + 1);
108
+ setTimeout(() => tryListen(retriesLeft - 1).then(resolve, reject), delay);
109
+ }
110
+ else {
111
+ reject(err);
112
+ }
113
+ });
114
+ server.listen(sockPath, () => {
115
+ // Set socket file permissions (Unix only)
116
+ if (process.platform !== 'win32') {
117
+ try {
118
+ fs.chmodSync(sockPath, 0o600);
119
+ }
120
+ catch { /* best effort */ }
121
+ }
122
+ socketServer = server;
123
+ resolve();
124
+ });
125
+ });
126
+ // Increase retries on Windows where named pipes take longer to release
127
+ // In tests, we retry more aggressively; in production the default is sufficient
128
+ const maxRetries = process.platform === 'win32' ? (process.env.NODE_ENV === 'test' ? 10 : 5) : 0;
129
+ return tryListen(maxRetries);
130
+ }
131
+ export function createPendingAuth(memberName) {
132
+ // Clean expired entries
133
+ const now = Date.now();
134
+ for (const [name, entry] of pendingRequests) {
135
+ if (now - entry.createdAt > PENDING_TTL_MS) {
136
+ pendingRequests.delete(name);
137
+ }
138
+ }
139
+ pendingRequests.set(memberName, { createdAt: now });
140
+ }
141
+ export function getPendingPassword(memberName) {
142
+ const entry = pendingRequests.get(memberName);
143
+ if (!entry)
144
+ return null;
145
+ if (Date.now() - entry.createdAt > PENDING_TTL_MS) {
146
+ pendingRequests.delete(memberName);
147
+ return null;
148
+ }
149
+ if (!entry.encryptedPassword)
150
+ return null;
151
+ // Consume the entry
152
+ const pw = entry.encryptedPassword;
153
+ pendingRequests.delete(memberName);
154
+ return pw;
155
+ }
156
+ /**
157
+ * Deliver a plaintext credential to a pending auth request: encrypt it
158
+ * immediately, store it on the pending entry, and resolve any waiting tool
159
+ * handler. Shared by the socket handler (CLI entry) and the browser fallback
160
+ * (local web UI entry) so both delivery paths behave identically.
161
+ */
162
+ export function submitPassword(memberName, plaintext, persist) {
163
+ const pending = pendingRequests.get(memberName);
164
+ if (!pending)
165
+ return { ok: false, error: `No pending auth for ${memberName}` };
166
+ // Encrypt immediately; plaintext is never stored or logged.
167
+ pending.encryptedPassword = encryptPassword(plaintext);
168
+ if (persist !== undefined)
169
+ pending.persist = !!persist;
170
+ // Kill the spawned terminal process if one was launched.
171
+ if (pending.spawned_pid) {
172
+ killProcess(pending.spawned_pid);
173
+ pending.spawned_pid = undefined;
174
+ }
175
+ const waiter = passwordWaiters.get(memberName);
176
+ if (waiter) {
177
+ clearTimeout(waiter.timer);
178
+ passwordWaiters.delete(memberName);
179
+ waiter.resolve(pending.encryptedPassword);
180
+ }
181
+ return { ok: true };
182
+ }
183
+ /**
184
+ * Wait for a pending auth password to arrive over the socket.
185
+ * Returns the encrypted password, or rejects on timeout.
186
+ */
187
+ export function waitForPassword(memberName, timeoutMs = OOB_TIMEOUT_MS) {
188
+ // Race: password may have arrived before we started waiting
189
+ const existing = getPendingPassword(memberName);
190
+ if (existing)
191
+ return Promise.resolve(existing);
192
+ return new Promise((resolve, reject) => {
193
+ const timer = setTimeout(() => {
194
+ passwordWaiters.delete(memberName);
195
+ const pending = pendingRequests.get(memberName);
196
+ if (pending?.spawned_pid)
197
+ killProcess(pending.spawned_pid);
198
+ pendingRequests.delete(memberName);
199
+ reject(new Error(`Password entry timed out for ${memberName}`));
200
+ }, timeoutMs);
201
+ passwordWaiters.set(memberName, { resolve, reject, timer });
202
+ });
203
+ }
204
+ export function cancelPendingAuth(memberName) {
205
+ const pending = pendingRequests.get(memberName);
206
+ if (pending?.spawned_pid)
207
+ killProcess(pending.spawned_pid);
208
+ const waiter = passwordWaiters.get(memberName);
209
+ if (waiter) {
210
+ clearTimeout(waiter.timer);
211
+ waiter.reject(new Error('cancelled'));
212
+ }
213
+ passwordWaiters.delete(memberName);
214
+ pendingRequests.delete(memberName);
215
+ }
216
+ export function hasPendingAuth(memberName) {
217
+ const entry = pendingRequests.get(memberName);
218
+ if (!entry)
219
+ return false;
220
+ if (Date.now() - entry.createdAt > PENDING_TTL_MS) {
221
+ pendingRequests.delete(memberName);
222
+ return false;
223
+ }
224
+ return true;
225
+ }
226
+ export function cleanupAuthSocket() {
227
+ // If already closing, wait for it to finish.
228
+ // This ensures that we don't start a new server while the old one is still releasing the pipe.
229
+ if (closingPromise) {
230
+ return closingPromise;
231
+ }
232
+ // Reject any pending waiters immediately
233
+ for (const [, waiter] of passwordWaiters) {
234
+ clearTimeout(waiter.timer);
235
+ waiter.reject(new Error('Auth socket closed'));
236
+ }
237
+ passwordWaiters.clear();
238
+ pendingRequests.clear();
239
+ // Destroy all active client connections immediately
240
+ for (const s of activeSockets) {
241
+ s.destroy();
242
+ }
243
+ activeSockets.clear();
244
+ if (!socketServer) {
245
+ if (process.platform !== 'win32') {
246
+ try {
247
+ fs.unlinkSync(getSocketPath());
248
+ }
249
+ catch { /* ignore */ }
250
+ }
251
+ return Promise.resolve();
252
+ }
253
+ const server = socketServer;
254
+ socketServer = null; // Clear immediately so ensureAuthSocket knows we are closing
255
+ closingPromise = new Promise((resolve) => {
256
+ server.close(() => {
257
+ const onComplete = () => {
258
+ if (process.platform !== 'win32') {
259
+ try {
260
+ fs.unlinkSync(getSocketPath());
261
+ }
262
+ catch { /* ignore */ }
263
+ }
264
+ if (process.platform === 'win32' && process.env.NODE_ENV === 'test') {
265
+ testPipeGeneration++;
266
+ }
267
+ closingPromise = null;
268
+ resolve();
269
+ };
270
+ if (process.platform === 'win32' && process.env.NODE_ENV !== 'test') {
271
+ // Windows named pipes need extra time to be fully released by the OS.
272
+ // In test mode we use unique pipe names per generation, so no delay needed.
273
+ setTimeout(onComplete, 500);
274
+ }
275
+ else {
276
+ onComplete();
277
+ }
278
+ });
279
+ });
280
+ return closingPromise;
281
+ }
282
+ /**
283
+ * Core logic for out-of-band credential collection.
284
+ * Launches a terminal, then races a password waiter against a cancellation signal.
285
+ */
286
+ async function collectOobInput(mode, memberName, toolName, _opts) {
287
+ const launch = _opts?.launchFn ?? launchAuthTerminal;
288
+ const waitTimeoutMs = _opts?.waitTimeoutMs;
289
+ const modeArgs = mode === 'api-key' ? ['--api-key'] : mode === 'confirm' ? ['--confirm'] : [];
290
+ const promptArgs = _opts?.prompt ? ['--prompt', _opts.prompt] : [];
291
+ const extraArgs = [...modeArgs, ...promptArgs, ...(_opts?.additionalArgs ?? [])];
292
+ const inputType = mode === 'api-key' ? 'API key' : mode === 'confirm' ? 'confirmation' : 'Password';
293
+ const timeoutMessage = `❌ Password entry timed out for ${memberName}. Call ${toolName} again to retry.`;
294
+ const cancelledMessage = `❌ Password entry cancelled. Call ${toolName} again to retry.`;
295
+ // Re-entrant case
296
+ if (hasPendingAuth(memberName)) {
297
+ const encPw = getPendingPassword(memberName);
298
+ if (encPw)
299
+ return { password: encPw };
300
+ try {
301
+ // Another process already launched the terminal, just wait for the result.
302
+ return { password: await waitForPassword(memberName, waitTimeoutMs ?? OOB_TIMEOUT_MS) };
303
+ }
304
+ catch {
305
+ return { fallback: timeoutMessage };
306
+ }
307
+ }
308
+ await ensureAuthSocket();
309
+ createPendingAuth(memberName);
310
+ // Tear-down for the local browser UI if it ends up being the active
311
+ // collector; called on every exit path. A holder object (rather than a bare
312
+ // let) so the assignment inside the Promise executor below stays visible to
313
+ // the type checker at the call sites.
314
+ const webUi = { close: null };
315
+ try {
316
+ const passwordPromise = waitForPassword(memberName, waitTimeoutMs);
317
+ const cancellationPromise = new Promise((resolve, reject) => {
318
+ const result = launch(memberName, extraArgs, (exitCode) => {
319
+ if (exitCode !== 0) {
320
+ reject(new Error('cancelled'));
321
+ }
322
+ // If exit is 0, passwordPromise will win the race.
323
+ // We can resolve this with null to signal completion without a fallback.
324
+ resolve(null);
325
+ });
326
+ if (result.startsWith('fallback:')) {
327
+ // No terminal available. For credential entry, try the local browser UI
328
+ // before giving up to a manual CLI instruction. Confirm prompts and
329
+ // test-injected launchers stay on the original path.
330
+ if (mode !== 'confirm' && !_opts?.launchFn) {
331
+ const webPrompt = _opts?.prompt
332
+ ?? (mode === 'api-key' ? `Enter API key for ${memberName}` : `Enter SSH password for ${memberName}`);
333
+ const web = launchAuthWeb(memberName, mode, webPrompt, (value) => submitPassword(memberName, value));
334
+ if (web.kind === 'launched') {
335
+ webUi.close = web.close;
336
+ // Leave this promise pending: passwordPromise resolves when the
337
+ // browser POSTs the value, or rejects on timeout.
338
+ return;
339
+ }
340
+ }
341
+ const manualMsg = result.slice('fallback:'.length);
342
+ resolve({ fallback: `🔐 ${manualMsg}\n\nOnce the user has entered the ${inputType}, call ${toolName} again with the same parameters.` });
343
+ }
344
+ });
345
+ const raceResult = await Promise.race([passwordPromise, cancellationPromise]);
346
+ if (raceResult === null) {
347
+ // The terminal exited with code 0 (Windows `start /wait` always exits 0, even
348
+ // on user-close). Wait briefly for any in-flight socket message — if the user
349
+ // genuinely submitted, the password arrives within milliseconds of process exit.
350
+ // If nothing arrives in 500 ms, treat it as a user cancellation.
351
+ try {
352
+ const pw = await Promise.race([
353
+ passwordPromise,
354
+ new Promise((_, reject) => setTimeout(() => reject(new Error('cancelled')), 500)),
355
+ ]);
356
+ const persist = pendingRequests.get(memberName)?.persist;
357
+ pendingRequests.delete(memberName);
358
+ webUi.close?.();
359
+ return { password: pw, persist };
360
+ }
361
+ catch {
362
+ const waiter = passwordWaiters.get(memberName);
363
+ if (waiter) {
364
+ clearTimeout(waiter.timer);
365
+ passwordWaiters.delete(memberName);
366
+ }
367
+ pendingRequests.delete(memberName);
368
+ webUi.close?.();
369
+ return { fallback: cancelledMessage };
370
+ }
371
+ }
372
+ // Handle the fallback case from the cancellation promise
373
+ if (typeof raceResult === 'object' && raceResult?.fallback) {
374
+ // Clean up stale state so a retry can launch a fresh terminal.
375
+ // Without this, hasPendingAuth() returns true on the next call,
376
+ // the re-entrant path skips launchAuthTerminal, and the call hangs.
377
+ const waiter = passwordWaiters.get(memberName);
378
+ if (waiter) {
379
+ clearTimeout(waiter.timer);
380
+ passwordWaiters.delete(memberName);
381
+ }
382
+ pendingRequests.delete(memberName);
383
+ webUi.close?.();
384
+ return raceResult;
385
+ }
386
+ const persist = pendingRequests.get(memberName)?.persist;
387
+ pendingRequests.delete(memberName);
388
+ webUi.close?.();
389
+ return { password: raceResult, persist };
390
+ }
391
+ catch (err) {
392
+ // Clean up the pending request if the user cancelled.
393
+ const waiter = passwordWaiters.get(memberName);
394
+ if (waiter) {
395
+ clearTimeout(waiter.timer);
396
+ passwordWaiters.delete(memberName);
397
+ }
398
+ pendingRequests.delete(memberName);
399
+ webUi.close?.();
400
+ if (err.message === 'cancelled') {
401
+ return { fallback: cancelledMessage };
402
+ }
403
+ // It must be a timeout from waitForPassword
404
+ return { fallback: timeoutMessage };
405
+ }
406
+ }
407
+ /**
408
+ * Collect a password out-of-band.
409
+ * @see collectOobInput
410
+ */
411
+ export async function collectOobPassword(memberName, toolName, _opts) {
412
+ return collectOobInput('password', memberName, toolName, _opts);
413
+ }
414
+ /**
415
+ * Collect an API key out-of-band.
416
+ * @see collectOobInput
417
+ */
418
+ export async function collectOobApiKey(memberName, toolName, _opts) {
419
+ const additionalArgs = _opts?.askPersist ? ['--ask-persist'] : [];
420
+ return collectOobInput('api-key', memberName, toolName, { ...(_opts ?? {}), additionalArgs });
421
+ }
422
+ /**
423
+ * Prompt the user out-of-band to confirm a network-egress operation.
424
+ * Returns true if the user confirmed, false if they cancelled or timed out.
425
+ */
426
+ export async function collectOobConfirm(credentialName, _opts) {
427
+ const additionalArgs = [];
428
+ if (_opts?.command) {
429
+ additionalArgs.push('--context', _opts.command.slice(0, 200));
430
+ }
431
+ if (_opts?.memberName) {
432
+ additionalArgs.push('--on', _opts.memberName);
433
+ }
434
+ const result = await collectOobInput('confirm', credentialName, 'execute_command', {
435
+ ..._opts,
436
+ additionalArgs: additionalArgs.length > 0 ? additionalArgs : undefined,
437
+ });
438
+ if (result.fallback)
439
+ return { confirmed: false, terminalUnavailable: true };
440
+ return { confirmed: Boolean(result.password), terminalUnavailable: false };
441
+ }
442
+ /**
443
+ * Resolve the command to invoke this binary's `secret` subcommand.
444
+ * Confirm mode uses `secret --confirm`; all credential collection uses `secret --set`.
445
+ * Returns [command, ...args] suitable for spawn().
446
+ */
447
+ function getAuthCommand(memberName, extraArgs) {
448
+ const extra = extraArgs ?? [];
449
+ const isConfirm = extra.includes('--confirm');
450
+ let cmdArgs;
451
+ if (isConfirm) {
452
+ cmdArgs = ['secret', '--confirm', memberName];
453
+ }
454
+ else {
455
+ // All credential collection (password, API key) routes through `secret --set`
456
+ cmdArgs = ['secret', '--set', memberName];
457
+ const promptIdx = extra.indexOf('--prompt');
458
+ if (promptIdx !== -1 && promptIdx + 1 < extra.length) {
459
+ cmdArgs.push('--prompt', extra[promptIdx + 1]);
460
+ }
461
+ if (extra.includes('--ask-persist')) {
462
+ cmdArgs.push('--ask-persist');
463
+ }
464
+ }
465
+ // SEA binary: process.execPath is the binary itself
466
+ try {
467
+ const sea = require('node:sea');
468
+ if (sea.isSea()) {
469
+ return { cmd: process.execPath, args: cmdArgs };
470
+ }
471
+ }
472
+ catch { /* not SEA */ }
473
+ // Dev mode: node <path-to-index.js> <command>
474
+ const indexJs = path.resolve(path.dirname(new URL(import.meta.url).pathname), '..', 'index.js');
475
+ return { cmd: process.argv[0], args: [indexJs, ...cmdArgs] };
476
+ }
477
+ function buildHeadlessFallback(memberName, reason, context, extraArgs) {
478
+ const isConfirm = extraArgs?.includes('--confirm') ?? false;
479
+ let contextLines = '';
480
+ if (context?.onMember && context?.command) {
481
+ contextLines = `\n\n This command on ${context.onMember} will send credential "${memberName}" over the network:\n ${context.command}`;
482
+ }
483
+ else if (context?.command) {
484
+ contextLines = `\n\n Command: ${context.command}`;
485
+ }
486
+ if (isConfirm) {
487
+ return `fallback:${reason}${contextLines}\n\nRun this in a separate terminal to confirm:\n ! apra-fleet secret --confirm ${memberName}\n\nAlternatively, pre-store the value with credential_store_set and reference it as {{secure.NAME}} in the credential field.`;
488
+ }
489
+ return `fallback:${reason}${contextLines}\n\nRun this in a separate terminal to provide the credential:\n ! apra-fleet secret --set ${memberName}\n\nAlternatively, pre-store the value with credential_store_set and reference it as {{secure.NAME}} in the credential field.`;
490
+ }
491
+ /**
492
+ * Returns true when a graphical display is available on Linux/BSD.
493
+ * Checks $DISPLAY (X11) and $WAYLAND_DISPLAY (Wayland).
494
+ */
495
+ export function hasGraphicalDisplay() {
496
+ return Boolean(process.env.DISPLAY || process.env.WAYLAND_DISPLAY);
497
+ }
498
+ /**
499
+ * Returns true when the process is running inside an SSH session.
500
+ * SSH_TTY is set by the SSH daemon on both Linux and macOS when stdin is a tty.
501
+ */
502
+ export function isSSHSession() {
503
+ return !!process.env.SSH_TTY;
504
+ }
505
+ /**
506
+ * Returns true when running on an interactive Windows desktop session.
507
+ * SSH and headless service sessions have SESSIONNAME !== 'Console'.
508
+ */
509
+ export function hasInteractiveDesktop() {
510
+ return process.env.SESSIONNAME === 'Console';
511
+ }
512
+ /**
513
+ * Detect available terminal emulator on Linux/BSD.
514
+ * Checks $TERM_PROGRAM first (set by kitty, WezTerm, Ghostty, etc.) then
515
+ * probes a broad list ordered by popularity on modern distros.
516
+ * Each entry includes the exec-flag convention for that terminal.
517
+ */
518
+ function findLinuxTerminal() {
519
+ // $TERM_PROGRAM is set by several terminals when they launch a shell
520
+ const termProg = process.env.TERM_PROGRAM;
521
+ const termProgramMap = {
522
+ kitty: { bin: 'kitty', execArgs: [] },
523
+ WezTerm: { bin: 'wezterm', execArgs: ['start', '--'] },
524
+ ghostty: { bin: 'ghostty', execArgs: ['-e'] },
525
+ };
526
+ if (termProg && termProgramMap[termProg]) {
527
+ const entry = termProgramMap[termProg];
528
+ try {
529
+ execSync(`which ${entry.bin}`, { stdio: 'ignore' });
530
+ return entry;
531
+ }
532
+ catch { /* not in PATH, fall through */ }
533
+ }
534
+ // Ordered probe list: most common on modern Linux first
535
+ const candidates = [
536
+ { bin: 'kitty', execArgs: [] },
537
+ { bin: 'alacritty', execArgs: ['-e'] },
538
+ { bin: 'foot', execArgs: [] },
539
+ { bin: 'wezterm', execArgs: ['start', '--'] },
540
+ { bin: 'ghostty', execArgs: ['-e'] },
541
+ // --wait is required: without it, gnome-terminal hands the window off to
542
+ // gnome-terminal-server and the client process exits immediately (code 0).
543
+ // That premature exit makes collectOobInput see raceResult===null and fall
544
+ // through to the 500ms grace window, cancelling before the user can type.
545
+ // With --wait the client stays alive until the secret CLI exits.
546
+ { bin: 'gnome-terminal', execArgs: ['--wait', '--'] },
547
+ { bin: 'konsole', execArgs: ['-e'] },
548
+ { bin: 'xfce4-terminal', execArgs: ['-x'] },
549
+ { bin: 'mate-terminal', execArgs: ['-x'] },
550
+ { bin: 'x-terminal-emulator', execArgs: ['-e'] },
551
+ { bin: 'urxvt', execArgs: ['-e'] },
552
+ { bin: 'xterm', execArgs: ['-e'] },
553
+ { bin: 'st', execArgs: ['-e'] },
554
+ ];
555
+ for (const entry of candidates) {
556
+ try {
557
+ execSync(`which ${entry.bin}`, { stdio: 'ignore' });
558
+ return entry;
559
+ }
560
+ catch { /* not found */ }
561
+ }
562
+ return null;
563
+ }
564
+ /**
565
+ * Launch a new terminal window running `apra-fleet secret --set <memberName>` or `apra-fleet auth <memberName>`.
566
+ * Records the spawned PID in the pending request so it can be killed when credential is received.
567
+ * Returns a user-facing message describing what happened and executes a
568
+ * callback when the spawned terminal process exits.
569
+ */
570
+ export function launchAuthTerminal(memberName, extraArgs, onExit) {
571
+ const { cmd, args } = getAuthCommand(memberName, extraArgs);
572
+ const fullArgs = [cmd, ...args];
573
+ let child;
574
+ // Extract context args for headless fallback messages
575
+ const ctxIdx = extraArgs?.indexOf('--context') ?? -1;
576
+ const onIdx = extraArgs?.indexOf('--on') ?? -1;
577
+ const fallbackContext = {
578
+ command: ctxIdx !== -1 && extraArgs && ctxIdx + 1 < extraArgs.length ? extraArgs[ctxIdx + 1] : undefined,
579
+ onMember: onIdx !== -1 && extraArgs && onIdx + 1 < extraArgs.length ? extraArgs[onIdx + 1] : undefined,
580
+ };
581
+ try {
582
+ const platform = process.platform;
583
+ if (platform === 'win32' && !hasInteractiveDesktop()) {
584
+ return buildHeadlessFallback(memberName, 'No interactive desktop session detected (SSH or service context).', fallbackContext, extraArgs);
585
+ }
586
+ if (platform === 'linux' && !hasGraphicalDisplay()) {
587
+ return buildHeadlessFallback(memberName, 'No graphical display detected (SSH or headless session).', fallbackContext, extraArgs);
588
+ }
589
+ if (platform === 'darwin' && isSSHSession()) {
590
+ return buildHeadlessFallback(memberName, 'SSH session detected -- no terminal emulator available (SSH_TTY is set).', fallbackContext, extraArgs);
591
+ }
592
+ if (platform === 'darwin') {
593
+ // macOS: Use a complex AppleScript to wait for the window to close and get an exit code.
594
+ // This is memory-hardened by writing the exit code to a temp file.
595
+ (async () => {
596
+ let exitCode = 1; // Default to cancellation
597
+ const tmpFile = path.join(os.tmpdir(), `fleet-auth-exit-${Date.now()}`);
598
+ try {
599
+ // The command to run in the terminal. It must be a single string.
600
+ // It writes its own exit code to a temp file so we can read it later.
601
+ const command = [...fullArgs, `; echo $? > "${tmpFile}"`].join(' ');
602
+ // AppleScript to launch terminal, run command, and wait for it to be "not busy".
603
+ const appleScript = `
604
+ tell application "Terminal"
605
+ activate
606
+ set w to do script "${command.replace(/"/g, '\\"')}"
607
+ delay 1
608
+ repeat while busy of w
609
+ delay 0.5
610
+ end repeat
611
+ end tell
612
+ `;
613
+ const child = spawn('osascript', ['-']);
614
+ child.stdin.write(appleScript);
615
+ child.stdin.end();
616
+ child.on('close', async (code) => {
617
+ if (code !== 0) {
618
+ // osascript itself failed.
619
+ onExit(1);
620
+ return;
621
+ }
622
+ try {
623
+ const codeStr = await fsPromises.readFile(tmpFile, 'utf-8');
624
+ exitCode = parseInt(codeStr.trim(), 10);
625
+ if (isNaN(exitCode))
626
+ exitCode = 1;
627
+ }
628
+ catch {
629
+ exitCode = 1; // Assume cancellation if file not found (e.g., window closed manually)
630
+ }
631
+ finally {
632
+ await fsPromises.unlink(tmpFile).catch(() => { });
633
+ onExit(exitCode);
634
+ }
635
+ });
636
+ child.on('error', (err) => {
637
+ logError('auth_socket', `Failed to launch osascript for auth: ${err.message}`);
638
+ onExit(1);
639
+ });
640
+ }
641
+ catch (e) {
642
+ onExit(1); // Default to cancellation on any unexpected error.
643
+ }
644
+ })();
645
+ return 'launched';
646
+ }
647
+ else if (platform === 'win32') {
648
+ // Windows: start /wait ensures that the parent cmd.exe process waits for the new
649
+ // terminal window to be closed. This allows us to capture the exit event.
650
+ // The title argument to start is required.
651
+ const spawnArgs = ['/c', 'start', 'Fleet Password Entry', '/wait', ...fullArgs];
652
+ child = spawn('cmd', spawnArgs, { stdio: 'ignore' });
653
+ if (child.pid) {
654
+ const pending = pendingRequests.get(memberName);
655
+ if (pending)
656
+ pending.spawned_pid = child.pid;
657
+ }
658
+ }
659
+ else {
660
+ // Linux: find available terminal emulator and use its exec-flag convention.
661
+ const terminal = findLinuxTerminal();
662
+ if (!terminal) {
663
+ return `fallback:Could not find a terminal emulator. Ask the user to run manually:\n ${[cmd, ...args].join(' ')}\nAlternatively, pre-store the value with credential_store_set and reference it as {{secure.NAME}} in the credential field.`;
664
+ }
665
+ child = spawn(terminal.bin, [...terminal.execArgs, ...fullArgs], { detached: true, stdio: 'ignore' });
666
+ if (child.pid) {
667
+ const pending = pendingRequests.get(memberName);
668
+ if (pending)
669
+ pending.spawned_pid = child.pid;
670
+ }
671
+ }
672
+ child.on('close', onExit);
673
+ child.on('error', (err) => {
674
+ logError('auth_socket', `Failed to launch terminal for ${memberName}: ${err.message}`);
675
+ onExit(1); // Treat spawn error as a non-zero exit.
676
+ });
677
+ child.unref();
678
+ return 'launched';
679
+ }
680
+ catch (err) {
681
+ return `fallback:Could not open a terminal window. Ask the user to run manually:\n ${[cmd, ...args].join(' ')}\nError: ${err.message}\nAlternatively, pre-store the value with credential_store_set and reference it as {{secure.NAME}} in the credential field.`;
682
+ }
683
+ }
684
+ //# sourceMappingURL=auth-socket.js.map