dsh-cliworker-now 0.0.0-stage → 0.7.7

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 (344) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +364 -0
  3. package/README.md +368 -2
  4. package/cordis.patch.yml +3 -0
  5. package/lib/account-models.mjs +262 -0
  6. package/lib/client.js +22139 -0
  7. package/lib/client.js.map +1 -0
  8. package/lib/grok-catalog.mjs +145 -0
  9. package/lib/hermes-native-entry.py +96 -0
  10. package/lib/hermes-nous-refresh.py +331 -0
  11. package/lib/index.js +14544 -0
  12. package/lib/index.js.map +1 -0
  13. package/lib/native-launch.mjs +234 -0
  14. package/lib/native-spawn.mjs +32 -0
  15. package/lib/own-account-lease.mjs +105 -0
  16. package/lib/pi-installation.mjs +87 -0
  17. package/lib/pi-login.mjs +80 -0
  18. package/lib/pi-native-catalog.mjs +417 -0
  19. package/lib/pi-omp-bridge.mjs +602 -0
  20. package/lib/pi-omp-environment.mjs +15 -0
  21. package/lib/pi-omp-refresh.mjs +324 -0
  22. package/lib/private-launch.mjs +23 -0
  23. package/lib/terminal-bridge.mjs +18 -0
  24. package/lib/typert.host.d.ts +3 -0
  25. package/lib/typert.host.js +1430 -0
  26. package/lib/typert.remote-client.d.ts +72 -0
  27. package/lib/typert.remote-client.d.ts.map +1 -0
  28. package/lib/typert.remote-client.js +1256 -0
  29. package/lib/types/client/account-query-queue.d.ts +16 -0
  30. package/lib/types/client/account-query-queue.js +61 -0
  31. package/lib/types/client/account-query-queue.js.map +1 -0
  32. package/lib/types/client/account-terminal-css.d.ts +1 -0
  33. package/lib/types/client/account-terminal-css.js +3 -0
  34. package/lib/types/client/account-terminal-css.js.map +1 -0
  35. package/lib/types/client/account-terminal.d.ts +17 -0
  36. package/lib/types/client/account-terminal.js +525 -0
  37. package/lib/types/client/account-terminal.js.map +1 -0
  38. package/lib/types/client/assets/antigravity.png +0 -0
  39. package/lib/types/client/assets/claude-code.png +0 -0
  40. package/lib/types/client/assets/cliworker-now-logo.png +0 -0
  41. package/lib/types/client/assets/codex.png +0 -0
  42. package/lib/types/client/assets/grok.png +0 -0
  43. package/lib/types/client/assets/hermes.png +0 -0
  44. package/lib/types/client/assets/kimi-dark.png +0 -0
  45. package/lib/types/client/assets/kimi-light.png +0 -0
  46. package/lib/types/client/assets/mimo-code.png +0 -0
  47. package/lib/types/client/assets/omp.png +0 -0
  48. package/lib/types/client/assets/opencode.png +0 -0
  49. package/lib/types/client/assets/pi.png +0 -0
  50. package/lib/types/client/assets/zcode.png +0 -0
  51. package/lib/types/client/composer-keymap.d.ts +18 -0
  52. package/lib/types/client/composer-keymap.js +49 -0
  53. package/lib/types/client/composer-keymap.js.map +1 -0
  54. package/lib/types/client/conversation-timeline.d.ts +6 -0
  55. package/lib/types/client/conversation-timeline.js +65 -0
  56. package/lib/types/client/conversation-timeline.js.map +1 -0
  57. package/lib/types/client/copy-text.d.ts +5 -0
  58. package/lib/types/client/copy-text.js +45 -0
  59. package/lib/types/client/copy-text.js.map +1 -0
  60. package/lib/types/client/icons.d.ts +21 -0
  61. package/lib/types/client/icons.js +68 -0
  62. package/lib/types/client/icons.js.map +1 -0
  63. package/lib/types/client/index.d.ts +3 -0
  64. package/lib/types/client/index.js +124 -0
  65. package/lib/types/client/index.js.map +1 -0
  66. package/lib/types/client/management-styles.d.ts +1 -0
  67. package/lib/types/client/management-styles.js +17 -0
  68. package/lib/types/client/management-styles.js.map +1 -0
  69. package/lib/types/client/name-copy.d.ts +5 -0
  70. package/lib/types/client/name-copy.js +107 -0
  71. package/lib/types/client/name-copy.js.map +1 -0
  72. package/lib/types/client/native-job-overlay.d.ts +11 -0
  73. package/lib/types/client/native-job-overlay.js +129 -0
  74. package/lib/types/client/native-job-overlay.js.map +1 -0
  75. package/lib/types/client/operation-error.d.ts +2 -0
  76. package/lib/types/client/operation-error.js +12 -0
  77. package/lib/types/client/operation-error.js.map +1 -0
  78. package/lib/types/client/panel.d.ts +8 -0
  79. package/lib/types/client/panel.js +310 -0
  80. package/lib/types/client/panel.js.map +1 -0
  81. package/lib/types/client/rename-copy-styles.d.ts +1 -0
  82. package/lib/types/client/rename-copy-styles.js +21 -0
  83. package/lib/types/client/rename-copy-styles.js.map +1 -0
  84. package/lib/types/client/rename-worker.d.ts +9 -0
  85. package/lib/types/client/rename-worker.js +53 -0
  86. package/lib/types/client/rename-worker.js.map +1 -0
  87. package/lib/types/client/role-presets.d.ts +6 -0
  88. package/lib/types/client/role-presets.js +111 -0
  89. package/lib/types/client/role-presets.js.map +1 -0
  90. package/lib/types/client/settings-dialog.d.ts +13 -0
  91. package/lib/types/client/settings-dialog.js +442 -0
  92. package/lib/types/client/settings-dialog.js.map +1 -0
  93. package/lib/types/client/stat-popover.d.ts +10 -0
  94. package/lib/types/client/stat-popover.js +32 -0
  95. package/lib/types/client/stat-popover.js.map +1 -0
  96. package/lib/types/client/styles.d.ts +9 -0
  97. package/lib/types/client/styles.js +221 -0
  98. package/lib/types/client/styles.js.map +1 -0
  99. package/lib/types/client/telemetry.d.ts +11 -0
  100. package/lib/types/client/telemetry.js +24 -0
  101. package/lib/types/client/telemetry.js.map +1 -0
  102. package/lib/types/client/worker-card.d.ts +10 -0
  103. package/lib/types/client/worker-card.js +75 -0
  104. package/lib/types/client/worker-card.js.map +1 -0
  105. package/lib/types/client/worker-model-menu.d.ts +9 -0
  106. package/lib/types/client/worker-model-menu.js +136 -0
  107. package/lib/types/client/worker-model-menu.js.map +1 -0
  108. package/lib/types/client/workers.d.ts +21 -0
  109. package/lib/types/client/workers.js +59 -0
  110. package/lib/types/client/workers.js.map +1 -0
  111. package/lib/types/client/zcode-login-link-provider.d.ts +9 -0
  112. package/lib/types/client/zcode-login-link-provider.js +105 -0
  113. package/lib/types/client/zcode-login-link-provider.js.map +1 -0
  114. package/lib/types/client/zcode-login-link.d.ts +16 -0
  115. package/lib/types/client/zcode-login-link.js +194 -0
  116. package/lib/types/client/zcode-login-link.js.map +1 -0
  117. package/lib/types/host/account-identity.d.ts +16 -0
  118. package/lib/types/host/account-identity.js +126 -0
  119. package/lib/types/host/account-identity.js.map +1 -0
  120. package/lib/types/host/account-login.d.ts +10 -0
  121. package/lib/types/host/account-login.js +126 -0
  122. package/lib/types/host/account-login.js.map +1 -0
  123. package/lib/types/host/account-models.d.mts +21 -0
  124. package/lib/types/host/account-models.mjs +262 -0
  125. package/lib/types/host/accounts.d.ts +42 -0
  126. package/lib/types/host/accounts.js +945 -0
  127. package/lib/types/host/accounts.js.map +1 -0
  128. package/lib/types/host/adapters.d.ts +24 -0
  129. package/lib/types/host/adapters.js +380 -0
  130. package/lib/types/host/adapters.js.map +1 -0
  131. package/lib/types/host/agy-context.d.ts +8 -0
  132. package/lib/types/host/agy-context.js +122 -0
  133. package/lib/types/host/agy-context.js.map +1 -0
  134. package/lib/types/host/agy-models.d.ts +5 -0
  135. package/lib/types/host/agy-models.js +37 -0
  136. package/lib/types/host/agy-models.js.map +1 -0
  137. package/lib/types/host/agy-windows-account.d.ts +14 -0
  138. package/lib/types/host/agy-windows-account.js +104 -0
  139. package/lib/types/host/agy-windows-account.js.map +1 -0
  140. package/lib/types/host/authorized-catalog.d.ts +14 -0
  141. package/lib/types/host/authorized-catalog.js +35 -0
  142. package/lib/types/host/authorized-catalog.js.map +1 -0
  143. package/lib/types/host/bridge-protocol.d.ts +15 -0
  144. package/lib/types/host/bridge-protocol.js +80 -0
  145. package/lib/types/host/bridge-protocol.js.map +1 -0
  146. package/lib/types/host/claude-native-oauth.d.ts +17 -0
  147. package/lib/types/host/claude-native-oauth.js +272 -0
  148. package/lib/types/host/claude-native-oauth.js.map +1 -0
  149. package/lib/types/host/claude-own-route.d.ts +33 -0
  150. package/lib/types/host/claude-own-route.js +250 -0
  151. package/lib/types/host/claude-own-route.js.map +1 -0
  152. package/lib/types/host/cli-account-binding.d.ts +33 -0
  153. package/lib/types/host/cli-account-binding.js +540 -0
  154. package/lib/types/host/cli-account-binding.js.map +1 -0
  155. package/lib/types/host/cli-protocol.d.ts +27 -0
  156. package/lib/types/host/cli-protocol.js +212 -0
  157. package/lib/types/host/cli-protocol.js.map +1 -0
  158. package/lib/types/host/codex-account.d.ts +8 -0
  159. package/lib/types/host/codex-account.js +143 -0
  160. package/lib/types/host/codex-account.js.map +1 -0
  161. package/lib/types/host/codex-models.d.ts +6 -0
  162. package/lib/types/host/codex-models.js +169 -0
  163. package/lib/types/host/codex-models.js.map +1 -0
  164. package/lib/types/host/extended-adapters.d.ts +44 -0
  165. package/lib/types/host/extended-adapters.js +207 -0
  166. package/lib/types/host/extended-adapters.js.map +1 -0
  167. package/lib/types/host/first-party-account-context.d.ts +26 -0
  168. package/lib/types/host/first-party-account-context.js +55 -0
  169. package/lib/types/host/first-party-account-context.js.map +1 -0
  170. package/lib/types/host/first-party-models.d.ts +29 -0
  171. package/lib/types/host/first-party-models.js +459 -0
  172. package/lib/types/host/first-party-models.js.map +1 -0
  173. package/lib/types/host/grok-adapter.d.ts +44 -0
  174. package/lib/types/host/grok-adapter.js +293 -0
  175. package/lib/types/host/grok-adapter.js.map +1 -0
  176. package/lib/types/host/grok-models.d.ts +47 -0
  177. package/lib/types/host/grok-models.js +320 -0
  178. package/lib/types/host/grok-models.js.map +1 -0
  179. package/lib/types/host/harness-opencode-accounts.d.ts +17 -0
  180. package/lib/types/host/harness-opencode-accounts.js +80 -0
  181. package/lib/types/host/harness-opencode-accounts.js.map +1 -0
  182. package/lib/types/host/hermes-account-context.d.ts +8 -0
  183. package/lib/types/host/hermes-account-context.js +99 -0
  184. package/lib/types/host/hermes-account-context.js.map +1 -0
  185. package/lib/types/host/hermes-accounts.d.ts +19 -0
  186. package/lib/types/host/hermes-accounts.js +356 -0
  187. package/lib/types/host/hermes-accounts.js.map +1 -0
  188. package/lib/types/host/hermes-adapter.d.ts +93 -0
  189. package/lib/types/host/hermes-adapter.js +455 -0
  190. package/lib/types/host/hermes-adapter.js.map +1 -0
  191. package/lib/types/host/hermes-env.d.ts +4 -0
  192. package/lib/types/host/hermes-env.js +22 -0
  193. package/lib/types/host/hermes-env.js.map +1 -0
  194. package/lib/types/host/hermes-installation.d.ts +10 -0
  195. package/lib/types/host/hermes-installation.js +181 -0
  196. package/lib/types/host/hermes-installation.js.map +1 -0
  197. package/lib/types/host/hermes-models.d.ts +26 -0
  198. package/lib/types/host/hermes-models.js +328 -0
  199. package/lib/types/host/hermes-models.js.map +1 -0
  200. package/lib/types/host/hermes-native-entry.py +96 -0
  201. package/lib/types/host/hermes-nous-refresh.py +331 -0
  202. package/lib/types/host/hermes-nous.d.ts +53 -0
  203. package/lib/types/host/hermes-nous.js +343 -0
  204. package/lib/types/host/hermes-nous.js.map +1 -0
  205. package/lib/types/host/hermes-renewal.d.ts +27 -0
  206. package/lib/types/host/hermes-renewal.js +292 -0
  207. package/lib/types/host/hermes-renewal.js.map +1 -0
  208. package/lib/types/host/hermes-suppression.d.ts +7 -0
  209. package/lib/types/host/hermes-suppression.js +69 -0
  210. package/lib/types/host/hermes-suppression.js.map +1 -0
  211. package/lib/types/host/hermes-windows-installation.d.ts +5 -0
  212. package/lib/types/host/hermes-windows-installation.js +91 -0
  213. package/lib/types/host/hermes-windows-installation.js.map +1 -0
  214. package/lib/types/host/index.d.ts +140 -0
  215. package/lib/types/host/index.js +947 -0
  216. package/lib/types/host/index.js.map +1 -0
  217. package/lib/types/host/kimi-accounts.d.ts +17 -0
  218. package/lib/types/host/kimi-accounts.js +220 -0
  219. package/lib/types/host/kimi-accounts.js.map +1 -0
  220. package/lib/types/host/kimi-oauth-models.d.ts +14 -0
  221. package/lib/types/host/kimi-oauth-models.js +246 -0
  222. package/lib/types/host/kimi-oauth-models.js.map +1 -0
  223. package/lib/types/host/managed-agent.d.ts +4 -0
  224. package/lib/types/host/managed-agent.js +127 -0
  225. package/lib/types/host/managed-agent.js.map +1 -0
  226. package/lib/types/host/mimo-configuration.d.ts +22 -0
  227. package/lib/types/host/mimo-configuration.js +258 -0
  228. package/lib/types/host/mimo-configuration.js.map +1 -0
  229. package/lib/types/host/mimo-metadata-cache.d.ts +22 -0
  230. package/lib/types/host/mimo-metadata-cache.js +121 -0
  231. package/lib/types/host/mimo-metadata-cache.js.map +1 -0
  232. package/lib/types/host/native-capability-cache.d.ts +11 -0
  233. package/lib/types/host/native-capability-cache.js +94 -0
  234. package/lib/types/host/native-capability-cache.js.map +1 -0
  235. package/lib/types/host/native-launch.d.mts +2 -0
  236. package/lib/types/host/native-launch.mjs +234 -0
  237. package/lib/types/host/native-process.d.ts +5 -0
  238. package/lib/types/host/native-process.js +41 -0
  239. package/lib/types/host/native-process.js.map +1 -0
  240. package/lib/types/host/native-spawn.mjs +32 -0
  241. package/lib/types/host/opencode-adapter.d.ts +94 -0
  242. package/lib/types/host/opencode-adapter.js +507 -0
  243. package/lib/types/host/opencode-adapter.js.map +1 -0
  244. package/lib/types/host/opencode-native.d.ts +27 -0
  245. package/lib/types/host/opencode-native.js +403 -0
  246. package/lib/types/host/opencode-native.js.map +1 -0
  247. package/lib/types/host/own-account-lease.d.mts +5 -0
  248. package/lib/types/host/own-account-lease.mjs +105 -0
  249. package/lib/types/host/pi-installation.d.mts +7 -0
  250. package/lib/types/host/pi-installation.mjs +87 -0
  251. package/lib/types/host/pi-omp-accounts.d.ts +28 -0
  252. package/lib/types/host/pi-omp-accounts.js +175 -0
  253. package/lib/types/host/pi-omp-accounts.js.map +1 -0
  254. package/lib/types/host/pi-omp-adapter.d.ts +32 -0
  255. package/lib/types/host/pi-omp-adapter.js +190 -0
  256. package/lib/types/host/pi-omp-adapter.js.map +1 -0
  257. package/lib/types/host/pi-omp-environment.d.mts +1 -0
  258. package/lib/types/host/pi-omp-environment.mjs +15 -0
  259. package/lib/types/host/pi-omp-identity.d.ts +2 -0
  260. package/lib/types/host/pi-omp-identity.js +142 -0
  261. package/lib/types/host/pi-omp-identity.js.map +1 -0
  262. package/lib/types/host/pi-omp-logout.d.ts +3 -0
  263. package/lib/types/host/pi-omp-logout.js +152 -0
  264. package/lib/types/host/pi-omp-logout.js.map +1 -0
  265. package/lib/types/host/pi-omp-native.d.ts +71 -0
  266. package/lib/types/host/pi-omp-native.js +753 -0
  267. package/lib/types/host/pi-omp-native.js.map +1 -0
  268. package/lib/types/host/pi-omp-refresh.d.mts +7 -0
  269. package/lib/types/host/pi-omp-refresh.mjs +324 -0
  270. package/lib/types/host/private-launch.mjs +23 -0
  271. package/lib/types/host/process.d.ts +43 -0
  272. package/lib/types/host/process.js +134 -0
  273. package/lib/types/host/process.js.map +1 -0
  274. package/lib/types/host/protocol.d.ts +23 -0
  275. package/lib/types/host/protocol.js +112 -0
  276. package/lib/types/host/protocol.js.map +1 -0
  277. package/lib/types/host/roles.d.ts +34 -0
  278. package/lib/types/host/roles.js +80 -0
  279. package/lib/types/host/roles.js.map +1 -0
  280. package/lib/types/host/routing.d.ts +31 -0
  281. package/lib/types/host/routing.js +248 -0
  282. package/lib/types/host/routing.js.map +1 -0
  283. package/lib/types/host/runtime.d.ts +60 -0
  284. package/lib/types/host/runtime.js +598 -0
  285. package/lib/types/host/runtime.js.map +1 -0
  286. package/lib/types/host/storage.d.ts +48 -0
  287. package/lib/types/host/storage.js +449 -0
  288. package/lib/types/host/storage.js.map +1 -0
  289. package/lib/types/host/telemetry.d.ts +17 -0
  290. package/lib/types/host/telemetry.js +158 -0
  291. package/lib/types/host/telemetry.js.map +1 -0
  292. package/lib/types/host/windows-account-bootstrap.ps1 +44 -0
  293. package/lib/types/host/windows-account-launch.mjs +47 -0
  294. package/lib/types/host/windows-account-owner.ps1 +137 -0
  295. package/lib/types/host/windows-account-stdio.mjs +19 -0
  296. package/lib/types/host/windows-account-terminal.d.ts +17 -0
  297. package/lib/types/host/windows-account-terminal.js +208 -0
  298. package/lib/types/host/windows-account-terminal.js.map +1 -0
  299. package/lib/types/host/windows-agy-account.ps1 +81 -0
  300. package/lib/types/host/windows-cli-installation.d.ts +31 -0
  301. package/lib/types/host/windows-cli-installation.js +157 -0
  302. package/lib/types/host/windows-cli-installation.js.map +1 -0
  303. package/lib/types/host/windows-hidden-launch.mjs +49 -0
  304. package/lib/types/host/windows-hidden-process.d.ts +12 -0
  305. package/lib/types/host/windows-hidden-process.js +116 -0
  306. package/lib/types/host/windows-hidden-process.js.map +1 -0
  307. package/lib/types/host/zcode-account-models.d.ts +16 -0
  308. package/lib/types/host/zcode-account-models.js +114 -0
  309. package/lib/types/host/zcode-account-models.js.map +1 -0
  310. package/lib/types/host/zcode-adapter.d.ts +93 -0
  311. package/lib/types/host/zcode-adapter.js +808 -0
  312. package/lib/types/host/zcode-adapter.js.map +1 -0
  313. package/lib/types/host/zcode-grok-accounts.d.ts +30 -0
  314. package/lib/types/host/zcode-grok-accounts.js +408 -0
  315. package/lib/types/host/zcode-grok-accounts.js.map +1 -0
  316. package/lib/types/shared/accounts.d.ts +47 -0
  317. package/lib/types/shared/accounts.js +2 -0
  318. package/lib/types/shared/accounts.js.map +1 -0
  319. package/lib/types/shared/builtin-presets.d.ts +2 -0
  320. package/lib/types/shared/builtin-presets.js +231 -0
  321. package/lib/types/shared/builtin-presets.js.map +1 -0
  322. package/lib/types/shared/cli-settings.d.ts +5 -0
  323. package/lib/types/shared/cli-settings.js +2 -0
  324. package/lib/types/shared/cli-settings.js.map +1 -0
  325. package/lib/types/shared/model-presentation.d.ts +10 -0
  326. package/lib/types/shared/model-presentation.js +95 -0
  327. package/lib/types/shared/model-presentation.js.map +1 -0
  328. package/lib/types/shared/models.d.ts +7 -0
  329. package/lib/types/shared/models.js +35 -0
  330. package/lib/types/shared/models.js.map +1 -0
  331. package/lib/types/shared/telemetry.d.ts +18 -0
  332. package/lib/types/shared/telemetry.js +16 -0
  333. package/lib/types/shared/telemetry.js.map +1 -0
  334. package/lib/types/shared/types.d.ts +127 -0
  335. package/lib/types/shared/types.js +147 -0
  336. package/lib/types/shared/types.js.map +1 -0
  337. package/lib/windows-account-bootstrap.ps1 +44 -0
  338. package/lib/windows-account-launch.mjs +47 -0
  339. package/lib/windows-account-owner.ps1 +137 -0
  340. package/lib/windows-account-stdio.mjs +19 -0
  341. package/lib/windows-agy-account.ps1 +81 -0
  342. package/lib/windows-hidden-launch.mjs +49 -0
  343. package/lib/zcode-resume.mjs +423 -0
  344. package/package.json +109 -4
@@ -0,0 +1,96 @@
1
+ """Use a verified current native venv with a separate account home, without installing.
2
+
3
+ The official launcher, checkout-derived install key and committed facts are checked by
4
+ Host. Recheck facts under the same install lock, then use Hermes' own generation lease.
5
+ No account/config content is copied, imported from another home, or printed here.
6
+ """
7
+ import json
8
+ import os
9
+ from pathlib import Path
10
+ import contextlib
11
+ import logging
12
+ import runpy
13
+ import stat
14
+ import sys
15
+
16
+ checkout, facts, environment = map(Path, sys.argv[1:4])
17
+ arguments = sys.argv[4:]
18
+
19
+ def selected():
20
+ if facts.is_symlink():
21
+ raise RuntimeError("Invalid Hermes installation record")
22
+ fd = os.open(facts, os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0) | getattr(os, "O_NONBLOCK", 0))
23
+ with os.fdopen(fd, encoding="utf-8-sig") as stream:
24
+ info = os.fstat(stream.fileno())
25
+ if not stat.S_ISREG(info.st_mode) or info.st_nlink != 1 or info.st_size > 4 * 1024 * 1024:
26
+ raise RuntimeError("Invalid Hermes installation record")
27
+ return json.load(stream).get("packages", {}).get("venv", {}).get("environment") == str(environment)
28
+
29
+ def run_entry():
30
+ release_holder = []
31
+ try:
32
+ return enter(release_holder)
33
+ finally:
34
+ for release in release_holder:
35
+ release()
36
+
37
+
38
+ def enter(release_holder):
39
+ if any(path.resolve() != path for path in (checkout, facts, environment)):
40
+ raise RuntimeError("Hermes installation changed; reopen login settings")
41
+ sys.path.insert(0, str(checkout))
42
+ with open(facts.parent / ".install.lock", "a+b") as lock:
43
+ if os.name == "nt":
44
+ from pm.filesystem import lock_fd
45
+ if not lock_fd(lock.fileno(), wait=False):
46
+ raise RuntimeError("Hermes installation is being updated; retry after it finishes")
47
+ else:
48
+ import fcntl
49
+ fcntl.flock(lock.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
50
+ if not selected():
51
+ raise RuntimeError("Hermes installation changed; reopen login settings")
52
+ from hermes_cli.runtime_state import lease_generation
53
+ release_holder.append(lease_generation(environment))
54
+ os.environ["HERMES_DISABLE_LAZY_INSTALLS"] = "1"
55
+ os.environ.pop("PYTHONHOME", None)
56
+ os.environ.pop("PYTHONPATH", None)
57
+ os.environ.pop("VIRTUAL_ENV", None)
58
+ sys.argv = [str(checkout / "hermes_cli/main.py"), *arguments]
59
+ # The native API exposes these boundaries, but main/run_agent pass the
60
+ # checkout's .env as a fallback. Pin its own home and disable that fallback
61
+ # and secret-manager hydration before either module imports the function.
62
+ # No parser or provider/login flow is replaced.
63
+ account_home = Path(os.environ["HERMES_HOME"])
64
+ if (account_home / ".cliworker-managed").exists() or (account_home / ".op.env").exists():
65
+ raise RuntimeError("Hermes plugin login cannot use additional account configuration layers")
66
+ from hermes_cli import env_loader
67
+ native_dotenv = env_loader.load_hermes_dotenv
68
+ def own_dotenv(**_options):
69
+ if (account_home / ".cliworker-managed").exists():
70
+ raise RuntimeError("Hermes plugin login cannot use an additional managed configuration")
71
+ if (account_home / ".op.env").exists():
72
+ raise RuntimeError("Hermes plugin login supports its own .env; external secret stores are unavailable")
73
+ return native_dotenv(hermes_home=account_home, project_env=None, load_external_secrets=False)
74
+ env_loader.load_hermes_dotenv = own_dotenv
75
+ if arguments and arguments[0].startswith("--cliworker-"):
76
+ if len(arguments) != 2 or arguments[0] != "--cliworker-nous-refresh":
77
+ return "unsupported"
78
+ own_dotenv()
79
+ operation = runpy.run_path(str(Path(__file__).with_name("hermes-nous-refresh.py")))
80
+ return operation["refresh_selected_nous"](account_home, arguments[1])
81
+ from hermes_cli.main import main
82
+ raise SystemExit(main())
83
+
84
+
85
+ if arguments and arguments[0].startswith("--cliworker-"):
86
+ # Fixed private operation has no native diagnostic/credential output. Keep
87
+ # SystemExit/KeyboardInterrupt semantics; ordinary failures are classified.
88
+ with open(os.devnull, "w") as quiet, contextlib.redirect_stdout(quiet), contextlib.redirect_stderr(quiet):
89
+ logging.disable(logging.CRITICAL)
90
+ try:
91
+ result = run_entry()
92
+ except Exception:
93
+ result = "unavailable"
94
+ print(json.dumps({"version": 1, "state": result}, separators=(",", ":")))
95
+ else:
96
+ run_entry()
@@ -0,0 +1,331 @@
1
+ """One bounded, same-account Nous renewal inside the verified native environment.
2
+
3
+ This module is loaded only by our fixed native-entry operation. Native OAuth
4
+ owns token exchange and atomic persistence. No resolver, pool selection, login,
5
+ anonymous identity, browser, model request or credential output is permitted.
6
+ """
7
+ import base64
8
+ import contextlib
9
+ import hashlib
10
+ import inspect
11
+ import json
12
+ import logging
13
+ import math
14
+ import os
15
+ from pathlib import Path
16
+ import re
17
+ import signal
18
+ import stat
19
+ import time
20
+
21
+ PORTAL = "https://portal.nousresearch.com"
22
+ INFERENCE = "https://inference-api.nousresearch.com/v1"
23
+ CLIENT = "hermes-cli"
24
+ MAX_FILE = 4 * 1024 * 1024
25
+ TOKEN_FIELDS = (
26
+ "access_token", "refresh_token", "token_type", "scope", "client_id",
27
+ "portal_base_url", "inference_base_url", "obtained_at", "expires_at", "expires_in",
28
+ "agent_key", "agent_key_id", "agent_key_expires_at", "agent_key_expires_in",
29
+ "agent_key_reused", "agent_key_obtained_at", "tls",
30
+ )
31
+ TERMINAL = {"invalid_grant", "invalid_token", "refresh_token_reused", "nous_auth_missing_refresh_token"}
32
+
33
+
34
+ class Refusal(Exception):
35
+ def __init__(self, state="changed"):
36
+ self.state = state
37
+
38
+
39
+ def text(value):
40
+ return isinstance(value, str) and 0 < len(value) <= 32768 and not re.search(r"[\x00-\x20\x7f]", value)
41
+
42
+
43
+ def canonical(value, expected):
44
+ return isinstance(value, str) and value.rstrip("/") == expected
45
+
46
+
47
+ def claims(token):
48
+ if not text(token) or not re.fullmatch(r"[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+", token):
49
+ raise Refusal()
50
+ raw = token.split(".")[1]
51
+ value = json.loads(base64.urlsafe_b64decode(raw + "=" * (-len(raw) % 4)))
52
+ if not isinstance(value, dict):
53
+ raise Refusal()
54
+ return value
55
+
56
+
57
+ def scope_values(value):
58
+ if isinstance(value, str):
59
+ return re.split(r"[\s,]+", value)
60
+ if isinstance(value, list):
61
+ return [part for item in value for part in scope_values(item)]
62
+ return []
63
+
64
+
65
+ def identity(state):
66
+ if not isinstance(state, dict) or state.get("auth_method") == "anonymous" or state.get("account_tier") == "anonymous":
67
+ raise Refusal()
68
+ token = claims(state.get("access_token"))
69
+ if token.get("account_tier") == "anonymous" or any(not text(token.get(key)) for key in ("sub", "org_id", "iss")):
70
+ raise Refusal()
71
+ client = token.get("client_id", "")
72
+ if client is None:
73
+ client = ""
74
+ if client != "" and not text(client):
75
+ raise Refusal()
76
+ expiry = token.get("exp")
77
+ if isinstance(expiry, bool) or not isinstance(expiry, (int, float)) or not math.isfinite(expiry):
78
+ raise Refusal()
79
+ if "inference:invoke" not in (scope_values(state.get("scope")) + scope_values(token.get("scope")) + scope_values(token.get("scp"))):
80
+ raise Refusal()
81
+ if not canonical(state.get("portal_base_url"), PORTAL) or not canonical(state.get("inference_base_url"), INFERENCE):
82
+ raise Refusal()
83
+ native_client = state.get("client_id") or CLIENT
84
+ if not text(native_client):
85
+ raise Refusal()
86
+ key = ["hermes-nous-v1", token["sub"], token["org_id"], token["iss"], client, PORTAL, INFERENCE]
87
+ digest = hashlib.sha256(json.dumps(key, ensure_ascii=False, separators=(",", ":")).encode("utf-8")).hexdigest()
88
+ return digest, native_client, float(expiry)
89
+
90
+
91
+ def regular_file(path, *, optional=False):
92
+ try:
93
+ info = path.lstat()
94
+ except FileNotFoundError:
95
+ if optional:
96
+ return False
97
+ raise Refusal("unavailable")
98
+ if not stat.S_ISREG(info.st_mode) or info.st_nlink != 1 or info.st_size > MAX_FILE:
99
+ raise Refusal()
100
+ return True
101
+
102
+
103
+ def read_json(path):
104
+ value = json.loads(read_private_text(path))
105
+ if not isinstance(value, dict):
106
+ raise Refusal()
107
+ return value
108
+
109
+
110
+ def read_private_text(path):
111
+ regular_file(path)
112
+ fd = os.open(path, os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0) | getattr(os, "O_NONBLOCK", 0))
113
+ with os.fdopen(fd, "rb") as stream:
114
+ opened = os.fstat(stream.fileno())
115
+ current = path.lstat()
116
+ if (not stat.S_ISREG(opened.st_mode) or opened.st_nlink != 1 or opened.st_size > MAX_FILE
117
+ or stat.S_ISLNK(current.st_mode) or (opened.st_dev, opened.st_ino) != (current.st_dev, current.st_ino)):
118
+ raise Refusal()
119
+ data = stream.read(MAX_FILE + 1)
120
+ if len(data) > MAX_FILE:
121
+ raise Refusal()
122
+ return data.decode("utf-8-sig")
123
+
124
+
125
+ def check_configuration(home):
126
+ # The native entry has already loaded only this home's dotenv. Do not import
127
+ # main/config resolution, which can consult profiles or external sources.
128
+ import hermes_yaml as yaml
129
+ config_path = home / "config.yaml"
130
+ config = yaml.safe_load(read_private_text(config_path))
131
+ if not isinstance(config, dict) or not isinstance(config.get("model"), dict):
132
+ raise Refusal()
133
+ if (config.get("auth") or {}).get("adopt_external_logins") is not False:
134
+ raise Refusal()
135
+ model = config["model"]
136
+ if model.get("provider") != "nous" or (config.get("providers") or {}).get("nous", {}).get("enabled") is False:
137
+ raise Refusal()
138
+ if model.get("api_key") or model.get("extra_headers") or any(os.environ.get(k) for k in ("NOUS_API_KEY", "CUSTOM_API_KEY")):
139
+ raise Refusal()
140
+ if any(re.fullmatch(r"NOUS_API_KEY_\d+", k) and v for k, v in os.environ.items()):
141
+ raise Refusal()
142
+ for value in (model.get("base_url"), os.environ.get("NOUS_INFERENCE_BASE_URL"), os.environ.get("CUSTOM_BASE_URL")):
143
+ if value and not canonical(value, INFERENCE):
144
+ raise Refusal()
145
+ for name in ("NOUS_PORTAL_BASE_URL", "HERMES_PORTAL_BASE_URL"):
146
+ if os.environ.get(name) and not canonical(os.environ[name], PORTAL):
147
+ raise Refusal()
148
+ if model.get("api_mode") not in (None, "chat_completions", "anthropic_messages"):
149
+ raise Refusal()
150
+ if (config.get("nous") or {}).get("anthropic_wire", "chat") not in ("chat", "native", "auto"):
151
+ raise Refusal()
152
+
153
+
154
+ def check_available(row):
155
+ if row.get("disabled") is True or row.get("status") == "exhausted" or row.get("last_status") == "dead":
156
+ raise Refusal("unavailable")
157
+ if row.get("last_status") == "exhausted":
158
+ until = row.get("last_error_reset_at")
159
+ if not isinstance(until, (int, float)) or isinstance(until, bool) or not math.isfinite(until) or until <= 0 or until > time.time():
160
+ raise Refusal("unavailable")
161
+ cooldowns = row.get("model_cooldowns", {})
162
+ if not isinstance(cooldowns, dict) or any(
163
+ isinstance(until, (int, float)) and not isinstance(until, bool) and until > time.time()
164
+ for until in cooldowns.values()
165
+ ):
166
+ raise Refusal("unavailable")
167
+
168
+
169
+ def checked_pool(store, state, expected):
170
+ if store.get("active_provider") != "nous" or state.get("agent_key") != state.get("access_token"):
171
+ raise Refusal()
172
+ if state.get("last_auth_error", {}).get("relogin_required") is True and not (state.get("access_token") or state.get("refresh_token")):
173
+ raise Refusal("relogin")
174
+ check_available(state)
175
+ rows = store.get("credential_pool", {}).get("nous")
176
+ if not isinstance(rows, list) or not 1 <= len(rows) <= 8:
177
+ raise Refusal()
178
+ for row in rows:
179
+ if not isinstance(row, dict) or row.get("auth_type") != "oauth" or row.get("source") not in ("device_code", "manual:device_code"):
180
+ raise Refusal()
181
+ if row.get("access_token") != state.get("access_token") or row.get("agent_key") != state.get("agent_key"):
182
+ raise Refusal()
183
+ if row.get("refresh_token") not in (None, state.get("refresh_token")):
184
+ raise Refusal()
185
+ for field, endpoint in (("portal_base_url", PORTAL), ("inference_base_url", INFERENCE), ("base_url", INFERENCE)):
186
+ if row.get(field) and not canonical(row[field], endpoint):
187
+ raise Refusal()
188
+ if (row.get("client_id") or CLIENT) != expected[1]:
189
+ raise Refusal()
190
+ check_available(row)
191
+ return rows
192
+
193
+
194
+ def checked_shared(shared, expected):
195
+ if shared.get("_schema") != 1 or not text(shared.get("refresh_token")):
196
+ raise Refusal()
197
+ found = identity(shared)
198
+ if found[:2] != expected[:2]:
199
+ raise Refusal()
200
+ return found
201
+
202
+
203
+ def _run(home, expected_digest, cancelled):
204
+ if not re.fullmatch(r"[a-f0-9]{64}", expected_digest or ""):
205
+ raise Refusal("unsupported")
206
+ from hermes_cli import auth
207
+ from hermes_constants import get_default_hermes_root
208
+ required = ("_provider_state_transaction", "_auth_file_path", "_nous_shared_store_path", "_nous_shared_store_lock",
209
+ "_save_provider_state_to_source", "_write_shared_nous_state", "_select_nous_invoke_jwt", "refresh_nous_oauth_from_state")
210
+ if any(not callable(getattr(auth, key, None)) for key in required):
211
+ raise Refusal("unsupported")
212
+ if "on_state_update" not in inspect.signature(auth.refresh_nous_oauth_from_state).parameters:
213
+ raise Refusal("unsupported")
214
+ home = Path(home)
215
+ if home != home.resolve() or not home.is_dir() or get_default_hermes_root().resolve() != home:
216
+ raise Refusal()
217
+ auth_path = home / "auth.json"
218
+ shared_path = auth._nous_shared_store_path()
219
+ if auth._auth_file_path().resolve() != auth_path or shared_path.parent != home / "shared" or shared_path.resolve() != shared_path:
220
+ raise Refusal()
221
+ if (home / "shared").exists() and not (home / "shared").is_dir():
222
+ raise Refusal()
223
+ check_configuration(home)
224
+ raw_ttl = os.environ.get("HERMES_NOUS_MIN_KEY_TTL_SECONDS", "120")
225
+ if not re.fullmatch(r"\d+", raw_ttl) or len(raw_ttl) > 9:
226
+ raise Refusal()
227
+ ttl = max(120, int(raw_ttl))
228
+ # Native cross-process ordering: auth first, shared second. No profile/global
229
+ # fallback or shared merge is allowed without the exact selected identity.
230
+ # Confirm the local provider exists before the native transaction can even
231
+ # consult a global fallback. Re-read under its lock to bind the snapshot.
232
+ if not isinstance(read_json(auth_path).get("providers", {}).get("nous"), dict):
233
+ raise Refusal()
234
+ with auth._provider_state_transaction("nous", timeout_seconds=1.0) as (store, state, source):
235
+ snapshot = read_json(auth_path)
236
+ if source is None or Path(source).resolve() != auth_path or not isinstance(store.get("providers", {}).get("nous"), dict):
237
+ raise Refusal()
238
+ if snapshot.get("providers", {}).get("nous") != state or snapshot.get("credential_pool") != store.get("credential_pool"):
239
+ raise Refusal()
240
+ check_configuration(home)
241
+ expected = identity(state)
242
+ if expected[0] != expected_digest:
243
+ raise Refusal()
244
+ rows = checked_pool(store, state, expected)
245
+ if cancelled[0]:
246
+ raise Refusal("unavailable")
247
+ with auth._nous_shared_store_lock(timeout_seconds=1.0):
248
+ shared = read_json(shared_path) if regular_file(shared_path, optional=True) else None
249
+ if shared is not None:
250
+ shared_identity = checked_shared(shared, expected)
251
+ different_pair = (shared.get("access_token"), shared.get("refresh_token")) != (state.get("access_token"), state.get("refresh_token"))
252
+ if different_pair and shared_identity[2] == expected[2]:
253
+ raise Refusal()
254
+ else:
255
+ shared_identity, different_pair = None, False
256
+
257
+ def persist(update, _reason=None):
258
+ nonlocal state
259
+ merged = {**state, **{key: update[key] for key in TOKEN_FIELDS if key in update}}
260
+ if identity(merged)[:2] != expected[:2]:
261
+ raise Refusal()
262
+ # Select only this already identity-checked invoke JWT. This has
263
+ # no network/I/O and keeps pool aliases consistent even if the
264
+ # pure refresher's later validation fails after token rotation.
265
+ auth._select_nous_invoke_jwt(merged)
266
+ if merged.get("agent_key") != merged.get("access_token"):
267
+ raise Refusal("unsupported")
268
+ for row in rows:
269
+ for key in TOKEN_FIELDS:
270
+ if key in merged:
271
+ row[key] = merged[key]
272
+ auth._save_provider_state_to_source(store, "nous", merged, source)
273
+ state = merged
274
+ # Native mirror is best-effort, so verify the saved pair before
275
+ # reporting ready. No outside-home store is ever touched.
276
+ auth._write_shared_nous_state(state)
277
+ saved = read_json(shared_path)
278
+ if checked_shared(saved, expected)[:2] != expected[:2] or any(saved.get(k) != state.get(k) for k in ("access_token", "refresh_token")):
279
+ raise Refusal("unavailable")
280
+
281
+ # A newer peer rotation for this exact principal/client/route may
282
+ # be adopted. Equal-expiry differing tokens are not a proven chain.
283
+ if different_pair and shared_identity[2] > expected[2]:
284
+ persist(shared)
285
+ elif different_pair:
286
+ # The selected store is provably newer. Repair this same-home,
287
+ # same-principal mirror before a native resolver can adopt its
288
+ # older single-use refresh token back into the selected store.
289
+ persist(state)
290
+ current = identity(state)
291
+ if current[2] > time.time() + ttl:
292
+ return "ready"
293
+ if not text(state.get("refresh_token")):
294
+ raise Refusal("relogin")
295
+ if cancelled[0]:
296
+ raise Refusal("unavailable")
297
+ refreshed = auth.refresh_nous_oauth_from_state(
298
+ state, timeout_seconds=4.0, force_refresh=True, on_state_update=persist)
299
+ persist(refreshed)
300
+ if identity(state)[2] <= time.time() + 120:
301
+ raise Refusal("unavailable")
302
+ return "unavailable" if cancelled[0] else "ready"
303
+
304
+
305
+ def refresh_selected_nous(home, expected_digest):
306
+ """Fixed safe receipt only. Exceptions and logs never cross the boundary."""
307
+ cancelled = [False]
308
+ handlers = {}
309
+ def on_cancel(_signal, _frame):
310
+ # Do not interrupt a successful single-use token exchange before its
311
+ # callback saves the rotation. Host must also await this bounded child
312
+ # on Windows, where Job termination cannot be deferred by Python.
313
+ cancelled[0] = True
314
+ for number in (signal.SIGTERM, signal.SIGINT):
315
+ handlers[number] = signal.signal(number, on_cancel)
316
+ old_disable = logging.root.manager.disable
317
+ try:
318
+ with open(os.devnull, "w") as quiet, contextlib.redirect_stdout(quiet), contextlib.redirect_stderr(quiet):
319
+ logging.disable(logging.CRITICAL)
320
+ try:
321
+ return _run(home, expected_digest, cancelled)
322
+ except Refusal as error:
323
+ return error.state
324
+ except Exception as error:
325
+ if getattr(error, "code", None) in TERMINAL and bool(getattr(error, "relogin_required", False)):
326
+ return "relogin"
327
+ return "unavailable"
328
+ finally:
329
+ logging.disable(old_disable)
330
+ for number, handler in handlers.items():
331
+ signal.signal(number, handler)
@@ -0,0 +1,53 @@
1
+ import type { Effort } from '../shared/types.ts';
2
+ import type { AccountModelScope } from './account-models.mjs';
3
+ export declare const NOUS_PORTAL = "https://portal.nousresearch.com";
4
+ export declare const NOUS_INFERENCE = "https://inference-api.nousresearch.com/v1";
5
+ export declare class HermesNousError extends Error {
6
+ constructor(message: string);
7
+ }
8
+ export interface HermesNousSource {
9
+ /** Host only. Never serialize this object in a public response or on disk. */
10
+ access: string;
11
+ agentKey: string;
12
+ expires: number;
13
+ email?: string;
14
+ principal: {
15
+ kind: 'oauth';
16
+ subject: string;
17
+ organization: string;
18
+ issuer: string;
19
+ clientId?: string;
20
+ };
21
+ route: {
22
+ portal: string;
23
+ inference: string;
24
+ anthropicWire?: string;
25
+ };
26
+ paidAccess?: boolean;
27
+ modelCooldowns: Record<string, unknown>[];
28
+ }
29
+ /** Hermes 6c80c327: flat providers.nous, native device-code pool and invoke JWT.
30
+ * No refresh-only, guest, fallback store or different pooled principal is promoted. */
31
+ export declare function projectHermesNousSource(auth: any, minTtlSeconds?: number, options?: {
32
+ allowExpired?: boolean;
33
+ }): HermesNousSource;
34
+ export declare function hermesNousMinimumTtl(env: Record<string, string>): number;
35
+ /** Runtime uses its supported MIN_KEY_TTL override (120s), matching the native
36
+ * invoke-JWT skew. The native default 1800s is a proactive-refresh optimization,
37
+ * not invalid-account evidence. An explicit own-home setting still takes precedence. */
38
+ export declare function selectHermesNousSource(material: {
39
+ config: any;
40
+ auth: any;
41
+ env: Record<string, string>;
42
+ }, options?: {
43
+ allowExpired?: boolean;
44
+ }): HermesNousSource;
45
+ export declare function hermesNousEfforts(home: string, source: HermesNousSource, model: string): Effort[];
46
+ export declare function beginHermesNousCapabilities(home: string, source: HermesNousSource): symbol;
47
+ export declare function forgetHermesNousCapabilities(home: string, source: HermesNousSource, generation: symbol): void;
48
+ /** Two read-only, authenticated native endpoints. No public fallback, retry or OAuth refresh. */
49
+ export declare function fetchHermesNousModels(home: string, source: HermesNousSource, options?: {
50
+ signal?: AbortSignal;
51
+ fetch?: typeof fetch;
52
+ timeoutMs?: number;
53
+ }, generation?: symbol): Promise<AccountModelScope>;