@galaxyproject/orbit 0.0.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (451) hide show
  1. package/CHANGELOG.md +123 -0
  2. package/LICENSE +21 -0
  3. package/README.md +760 -5
  4. package/bin/legacy-mcp-config.js +363 -0
  5. package/bin/orbit.js +810 -0
  6. package/bin/pi-extension-path.d.ts +4 -0
  7. package/bin/pi-extension-path.js +44 -0
  8. package/bin/provider-auth.d.ts +22 -0
  9. package/bin/provider-auth.js +77 -0
  10. package/bin/thinking-pref.js +38 -0
  11. package/bin/update-check.d.ts +15 -0
  12. package/bin/update-check.js +137 -0
  13. package/extensions/cli-update/index.ts +32 -0
  14. package/extensions/orbit/activity-hooks.ts +141 -0
  15. package/extensions/orbit/activity.ts +116 -0
  16. package/extensions/orbit/agent-dir.ts +11 -0
  17. package/extensions/orbit/auto-resume.ts +352 -0
  18. package/extensions/orbit/config.ts +3 -0
  19. package/extensions/orbit/confusables.ts +1 -0
  20. package/extensions/orbit/context.ts +957 -0
  21. package/extensions/orbit/dashboard-commands.ts +191 -0
  22. package/extensions/orbit/dashboard-store.ts +473 -0
  23. package/extensions/orbit/dashboard-tools.ts +1185 -0
  24. package/extensions/orbit/empty-completion.ts +99 -0
  25. package/extensions/orbit/evidence-gate.ts +1276 -0
  26. package/extensions/orbit/evidence-override-command.ts +294 -0
  27. package/extensions/orbit/exec-guard/bash-risk.ts +1408 -0
  28. package/extensions/orbit/exec-guard/gate.ts +181 -0
  29. package/extensions/orbit/exec-guard/guardian-config.ts +54 -0
  30. package/extensions/orbit/exec-guard/index.ts +1 -0
  31. package/extensions/orbit/exec-guard/model-tier.ts +36 -0
  32. package/extensions/orbit/exec-guard/path-jail.ts +54 -0
  33. package/extensions/orbit/exec-guard/policy.ts +342 -0
  34. package/extensions/orbit/exec-guard/runtime-state.ts +15 -0
  35. package/extensions/orbit/exec-guard/sensitive-read.ts +525 -0
  36. package/extensions/orbit/exec-guard/types.ts +42 -0
  37. package/extensions/orbit/execution-commands.ts +134 -0
  38. package/extensions/orbit/feedback-command.ts +81 -0
  39. package/extensions/orbit/feedback.ts +96 -0
  40. package/extensions/orbit/galaxy-api.test.ts +122 -0
  41. package/extensions/orbit/galaxy-api.ts +606 -0
  42. package/extensions/orbit/galaxy-artifact-link-guidance.ts +5 -0
  43. package/extensions/orbit/galaxy-destructive-gate.ts +113 -0
  44. package/extensions/orbit/galaxy-enrich.ts +1108 -0
  45. package/extensions/orbit/galaxy-failure.ts +101 -0
  46. package/extensions/orbit/galaxy-fixture.ts +126 -0
  47. package/extensions/orbit/galaxy-history-guard.ts +233 -0
  48. package/extensions/orbit/galaxy-job-block.ts +347 -0
  49. package/extensions/orbit/galaxy-job-ops.ts +288 -0
  50. package/extensions/orbit/galaxy-live-source.ts +929 -0
  51. package/extensions/orbit/galaxy-markdown-adapter.ts +248 -0
  52. package/extensions/orbit/galaxy-op-policy.ts +332 -0
  53. package/extensions/orbit/galaxy-ops-tools.ts +326 -0
  54. package/extensions/orbit/galaxy-output-store.ts +80 -0
  55. package/extensions/orbit/galaxy-output.ts +346 -0
  56. package/extensions/orbit/galaxy-page-binding.ts +222 -0
  57. package/extensions/orbit/galaxy-page-markdown-guidance.ts +15 -0
  58. package/extensions/orbit/galaxy-page-ops.ts +159 -0
  59. package/extensions/orbit/galaxy-page-sync.test.ts +417 -0
  60. package/extensions/orbit/galaxy-page-sync.ts +318 -0
  61. package/extensions/orbit/galaxy-pages-api.ts +203 -0
  62. package/extensions/orbit/galaxy-pages-sync.ts +409 -0
  63. package/extensions/orbit/galaxy-poll-guard.ts +189 -0
  64. package/extensions/orbit/galaxy-poller.ts +706 -0
  65. package/extensions/orbit/galaxy-provenance.ts +623 -0
  66. package/extensions/orbit/galaxy-reconcile.ts +956 -0
  67. package/extensions/orbit/galaxy-recovery.ts +176 -0
  68. package/extensions/orbit/galaxy-repeat-guard.ts +55 -0
  69. package/extensions/orbit/galaxy-submission-capture.ts +707 -0
  70. package/extensions/orbit/galaxy-submission.ts +502 -0
  71. package/extensions/orbit/galaxy-tool-source.ts +78 -0
  72. package/extensions/orbit/galaxy-tool-wrap.ts +234 -0
  73. package/extensions/orbit/galaxy-udt-block.ts +127 -0
  74. package/extensions/orbit/galaxy-upload-tus.ts +334 -0
  75. package/extensions/orbit/galaxy-upload.ts +300 -0
  76. package/extensions/orbit/galaxy-version-capture.ts +65 -0
  77. package/extensions/orbit/git.ts +173 -0
  78. package/extensions/orbit/harness-block-fields.ts +597 -0
  79. package/extensions/orbit/index.ts +593 -0
  80. package/extensions/orbit/init-gate.ts +284 -0
  81. package/extensions/orbit/instructions-command.ts +136 -0
  82. package/extensions/orbit/invocation-failure-hint.ts +57 -0
  83. package/extensions/orbit/iwc-plan-check.ts +94 -0
  84. package/extensions/orbit/lesson-command.ts +303 -0
  85. package/extensions/orbit/lesson-hint.ts +245 -0
  86. package/extensions/orbit/lesson-nudge.ts +106 -0
  87. package/extensions/orbit/lessons/compose.ts +177 -0
  88. package/extensions/orbit/lessons/counters.ts +120 -0
  89. package/extensions/orbit/lessons/enabled.ts +116 -0
  90. package/extensions/orbit/lessons/matcher.ts +346 -0
  91. package/extensions/orbit/lessons/paths.ts +286 -0
  92. package/extensions/orbit/lessons/pi-event-contract.ts +105 -0
  93. package/extensions/orbit/lessons/propose-replay.ts +103 -0
  94. package/extensions/orbit/lessons/propose-tool.ts +222 -0
  95. package/extensions/orbit/lessons/propose.ts +502 -0
  96. package/extensions/orbit/lessons/replay.ts +89 -0
  97. package/extensions/orbit/lessons/reproduction-index.ts +83 -0
  98. package/extensions/orbit/lessons/search-tool.ts +99 -0
  99. package/extensions/orbit/lessons/search.ts +136 -0
  100. package/extensions/orbit/lessons/store.ts +415 -0
  101. package/extensions/orbit/lessons/text.ts +36 -0
  102. package/extensions/orbit/lessons/types.ts +69 -0
  103. package/extensions/orbit/lessons/user-dir.ts +24 -0
  104. package/extensions/orbit/lessons/user-lesson.ts +88 -0
  105. package/extensions/orbit/lessons/wrapper.ts +61 -0
  106. package/extensions/orbit/lessons-command.ts +147 -0
  107. package/extensions/orbit/local-exec.ts +39 -0
  108. package/extensions/orbit/mcp-output.ts +179 -0
  109. package/extensions/orbit/mcp-servers.test.ts +24 -0
  110. package/extensions/orbit/mcp-servers.ts +25 -0
  111. package/extensions/orbit/model-script.ts +351 -0
  112. package/extensions/orbit/notebook-anchors.ts +342 -0
  113. package/extensions/orbit/notebook-writer.ts +863 -0
  114. package/extensions/orbit/observation-allowlists.ts +1109 -0
  115. package/extensions/orbit/observation-replay.ts +148 -0
  116. package/extensions/orbit/observation-triggers.ts +563 -0
  117. package/extensions/orbit/observation-ui.ts +175 -0
  118. package/extensions/orbit/observations-command.ts +421 -0
  119. package/extensions/orbit/observations-config.ts +200 -0
  120. package/extensions/orbit/observations.ts +1381 -0
  121. package/extensions/orbit/profiles.ts +270 -0
  122. package/extensions/orbit/progress-updates.ts +95 -0
  123. package/extensions/orbit/proposal-commands.ts +882 -0
  124. package/extensions/orbit/provenance-fs-file.ts +59 -0
  125. package/extensions/orbit/provenance-fs.ts +32 -0
  126. package/extensions/orbit/provenance-memory-fs.ts +59 -0
  127. package/extensions/orbit/record-store-file.ts +177 -0
  128. package/extensions/orbit/record-store-page.ts +77 -0
  129. package/extensions/orbit/record-store-seam.ts +47 -0
  130. package/extensions/orbit/record-store.ts +149 -0
  131. package/extensions/orbit/registry-carrier.ts +107 -0
  132. package/extensions/orbit/registry-eligibility.ts +95 -0
  133. package/extensions/orbit/registry-evaluation.ts +403 -0
  134. package/extensions/orbit/registry-evaluator.ts +519 -0
  135. package/extensions/orbit/registry-import.ts +91 -0
  136. package/extensions/orbit/registry-lock.ts +221 -0
  137. package/extensions/orbit/registry-memory-fs.ts +42 -0
  138. package/extensions/orbit/registry-page-carrier.ts +103 -0
  139. package/extensions/orbit/registry-proposal.ts +1348 -0
  140. package/extensions/orbit/registry-runtime.ts +234 -0
  141. package/extensions/orbit/registry-schema.ts +735 -0
  142. package/extensions/orbit/registry-submitter.ts +59 -0
  143. package/extensions/orbit/registry-templates.ts +346 -0
  144. package/extensions/orbit/registry.ts +476 -0
  145. package/extensions/orbit/sandbox/index.ts +120 -0
  146. package/extensions/orbit/sandbox/sandbox-bash.ts +93 -0
  147. package/extensions/orbit/sandbox/sandbox-config.ts +87 -0
  148. package/extensions/orbit/sandbox/sandbox-init-message.ts +28 -0
  149. package/extensions/orbit/secret-redaction.ts +247 -0
  150. package/extensions/orbit/session-index/cwd.ts +18 -0
  151. package/extensions/orbit/session-index/db.ts +56 -0
  152. package/extensions/orbit/session-index/indexer.ts +154 -0
  153. package/extensions/orbit/session-index/is-enabled.ts +17 -0
  154. package/extensions/orbit/session-index/parse.ts +254 -0
  155. package/extensions/orbit/session-index/query.ts +209 -0
  156. package/extensions/orbit/session-index/schema.ts +72 -0
  157. package/extensions/orbit/session-index/tools.ts +152 -0
  158. package/extensions/orbit/session-lifecycle.ts +321 -0
  159. package/extensions/orbit/skill-triggers.ts +159 -0
  160. package/extensions/orbit/skills-command.ts +48 -0
  161. package/extensions/orbit/skills-discovery.ts +435 -0
  162. package/extensions/orbit/skills.ts +84 -0
  163. package/extensions/orbit/sra-import-gate.ts +77 -0
  164. package/extensions/orbit/state.ts +265 -0
  165. package/extensions/orbit/submission-replay.ts +147 -0
  166. package/extensions/orbit/sync-command.ts +157 -0
  167. package/extensions/orbit/teams/critic-parser.ts +93 -0
  168. package/extensions/orbit/teams/dispatcher.ts +210 -0
  169. package/extensions/orbit/teams/is-enabled.ts +22 -0
  170. package/extensions/orbit/teams/tool.ts +187 -0
  171. package/extensions/orbit/teams/types.ts +57 -0
  172. package/extensions/orbit/teams/validate.ts +42 -0
  173. package/extensions/orbit/tester-id-command.ts +133 -0
  174. package/extensions/orbit/tools-sync.ts +279 -0
  175. package/extensions/orbit/tools.ts +1300 -0
  176. package/extensions/orbit/types.ts +41 -0
  177. package/extensions/orbit/ui-bridge.ts +55 -0
  178. package/extensions/orbit/ulid.ts +60 -0
  179. package/extensions/orbit/user-instructions.ts +388 -0
  180. package/extensions/orbit/vendor/skills/_catalog.json +68 -0
  181. package/extensions/orbit/vendor/skills/_manifest.json +1106 -0
  182. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/SKILL.md +112 -0
  183. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/_provenance.json +218 -0
  184. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/_required_tools.json +33 -0
  185. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/_verify.json +4 -0
  186. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/add.json +50 -0
  187. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/draft-extract.json +51 -0
  188. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/draft-next-step.json +42 -0
  189. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/draft-validate.json +140 -0
  190. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/list.json +32 -0
  191. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/notes/galaxy-tool-job-failure-reference.md +137 -0
  192. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/notes/open-requirements-ledger.md +173 -0
  193. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/schemas/galaxy-tool-summary.schema.json +175 -0
  194. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/schemas/galaxy-workflow-draft.schema.json +2727 -0
  195. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/SKILL.md +82 -0
  196. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/_provenance.json +133 -0
  197. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/_required_tools.json +16 -0
  198. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/_verify.json +4 -0
  199. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/references/cli/draft-validate.json +140 -0
  200. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/references/notes/galaxy-workflow-draft-format.md +135 -0
  201. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/references/notes/open-requirements-ledger.md +173 -0
  202. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/references/schemas/galaxy-workflow-draft.schema.json +2727 -0
  203. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/SKILL.md +84 -0
  204. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/_provenance.json +166 -0
  205. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/_verify.json +29 -0
  206. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/galaxy-workflow-testability-design.md +136 -0
  207. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/iwc-shortcuts-anti-patterns.md +357 -0
  208. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/iwc-test-data-conventions.md +308 -0
  209. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/planemo-asserts-idioms.md +246 -0
  210. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/planemo-workflow-test-architecture.md +151 -0
  211. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/schemas/galaxy-workflow-test-plan.schema.json +552 -0
  212. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/schemas/summary-galaxy-workflow.schema.json +687 -0
  213. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/schemas/tests-format.schema.json +7328 -0
  214. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/SKILL.md +127 -0
  215. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/_provenance.json +198 -0
  216. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/_required_tools.json +16 -0
  217. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/_verify.json +4 -0
  218. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/cli/convert.json +123 -0
  219. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/notes/galaxy-data-flow-draft-contract.md +129 -0
  220. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/notes/iwc-shortcuts-anti-patterns.md +357 -0
  221. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/notes/iwc-test-data-conventions.md +308 -0
  222. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/notes/open-requirements-ledger.md +173 -0
  223. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/SKILL.md +73 -0
  224. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/_provenance.json +160 -0
  225. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/_verify.json +4 -0
  226. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/galaxy-collection-semantics.md +43 -0
  227. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/galaxy-collection-semantics.yml +1250 -0
  228. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/galaxy-tool-job-failure-reference.md +137 -0
  229. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/galaxy-workflow-invocation-failure-reference.md +138 -0
  230. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/iwc-shortcuts-anti-patterns.md +357 -0
  231. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/nextflow-operators-to-galaxy-collection-recipes.md +98 -0
  232. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/planemo-asserts-idioms.md +246 -0
  233. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/planemo-workflow-test-architecture.md +151 -0
  234. package/extensions/orbit/vendor/skills/discover-shed-tool/SKILL.md +174 -0
  235. package/extensions/orbit/vendor/skills/discover-shed-tool/_provenance.json +130 -0
  236. package/extensions/orbit/vendor/skills/discover-shed-tool/_required_tools.json +18 -0
  237. package/extensions/orbit/vendor/skills/discover-shed-tool/_verify.json +17 -0
  238. package/extensions/orbit/vendor/skills/discover-shed-tool/references/cli/tool-revisions.json +48 -0
  239. package/extensions/orbit/vendor/skills/discover-shed-tool/references/cli/tool-search.json +95 -0
  240. package/extensions/orbit/vendor/skills/discover-shed-tool/references/cli/tool-versions.json +39 -0
  241. package/extensions/orbit/vendor/skills/discover-shed-tool/references/notes/component-tool-shed-search.md +230 -0
  242. package/extensions/orbit/vendor/skills/discover-shed-tool/references/schemas/galaxy-tool-discovery.schema.json +231 -0
  243. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/SKILL.md +93 -0
  244. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/_provenance.json +201 -0
  245. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/_required_tools.json +28 -0
  246. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/_verify.json +17 -0
  247. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/cli/planemo.md +44 -0
  248. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/cli/validate-tests.json +40 -0
  249. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/galaxy-workflow-testability-design.md +136 -0
  250. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/iwc-shortcuts-anti-patterns.md +357 -0
  251. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/iwc-test-data-conventions.md +308 -0
  252. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/planemo-asserts-idioms.md +246 -0
  253. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/planemo-workflow-test-architecture.md +151 -0
  254. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/schemas/galaxy-workflow-test-plan.schema.json +552 -0
  255. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/schemas/tests-format.schema.json +7328 -0
  256. package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/SKILL.md +81 -0
  257. package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/_provenance.json +93 -0
  258. package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/_verify.json +17 -0
  259. package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/references/notes/open-requirements-ledger.md +173 -0
  260. package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/references/schemas/summary-galaxy-workflow.schema.json +687 -0
  261. package/extensions/orbit/vendor/skills/pipeline-update-interview-to-galaxy/SKILL.md +81 -0
  262. package/extensions/orbit/vendor/skills/pipeline-update-interview-to-galaxy/_assembly.json +23 -0
  263. package/extensions/orbit/vendor/skills/run-workflow-test/SKILL.md +79 -0
  264. package/extensions/orbit/vendor/skills/run-workflow-test/_provenance.json +125 -0
  265. package/extensions/orbit/vendor/skills/run-workflow-test/_required_tools.json +28 -0
  266. package/extensions/orbit/vendor/skills/run-workflow-test/_verify.json +4 -0
  267. package/extensions/orbit/vendor/skills/run-workflow-test/references/cli/planemo.md +44 -0
  268. package/extensions/orbit/vendor/skills/run-workflow-test/references/cli/validate-tests.json +40 -0
  269. package/extensions/orbit/vendor/skills/run-workflow-test/references/notes/galaxy-workflow-invocation-failure-reference.md +138 -0
  270. package/extensions/orbit/vendor/skills/run-workflow-test/references/notes/planemo-asserts-idioms.md +246 -0
  271. package/extensions/orbit/vendor/skills/run-workflow-test/references/notes/planemo-workflow-test-architecture.md +151 -0
  272. package/extensions/orbit/vendor/skills/run-workflow-test/references/schemas/tests-format.schema.json +7328 -0
  273. package/extensions/orbit/vendor/skills/skills/LICENSE +21 -0
  274. package/extensions/orbit/vendor/skills/skills/collection-manipulation/README.md +39 -0
  275. package/extensions/orbit/vendor/skills/skills/collection-manipulation/SKILL.md +892 -0
  276. package/extensions/orbit/vendor/skills/skills/collection-manipulation/references/api-patterns.md +927 -0
  277. package/extensions/orbit/vendor/skills/skills/collection-manipulation/references/apply-rules.md +1482 -0
  278. package/extensions/orbit/vendor/skills/skills/collection-manipulation/references/test-patterns.md +996 -0
  279. package/extensions/orbit/vendor/skills/skills/collection-manipulation/references/tools.md +609 -0
  280. package/extensions/orbit/vendor/skills/skills/galaxy-data-libraries/SKILL.md +170 -0
  281. package/extensions/orbit/vendor/skills/skills/galaxy-integration/README.md +162 -0
  282. package/extensions/orbit/vendor/skills/skills/galaxy-integration/SKILL.md +99 -0
  283. package/extensions/orbit/vendor/skills/skills/galaxy-integration/examples/README.md +119 -0
  284. package/extensions/orbit/vendor/skills/skills/galaxy-integration/examples/tool-checking.md +419 -0
  285. package/extensions/orbit/vendor/skills/skills/galaxy-integration/examples/workflow-testing.md +617 -0
  286. package/extensions/orbit/vendor/skills/skills/galaxy-integration/galaxy-integration.md +614 -0
  287. package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/SKILL.md +144 -0
  288. package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/examples/average_col3.ipynb +68 -0
  289. package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/examples/extract_sample_metadata.ipynb +190 -0
  290. package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/examples/variant_annotation.ipynb +816 -0
  291. package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/examples/vcp_variant_map.ipynb +443 -0
  292. package/extensions/orbit/vendor/skills/skills/galaxy-integration/scripts/README.md +165 -0
  293. package/extensions/orbit/vendor/skills/skills/galaxy-integration/scripts/galaxy_tool_checker.py +521 -0
  294. package/extensions/orbit/vendor/skills/skills/galaxy-mcp-reference/SKILL.md +128 -0
  295. package/extensions/orbit/vendor/skills/skills/galaxy-mcp-reference/gotchas.md +135 -0
  296. package/extensions/orbit/vendor/skills/skills/galaxy-mcp-reference/history-access.md +132 -0
  297. package/extensions/orbit/vendor/skills/skills/reproduciblify/SKILL.md +146 -0
  298. package/extensions/orbit/vendor/skills/skills/reproduciblify/references/directives.yml +496 -0
  299. package/extensions/orbit/vendor/skills/skills/udt-authoring/SKILL.md +245 -0
  300. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/01-minimal-echo.yml +27 -0
  301. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/02-single-data-in-out.yml +27 -0
  302. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/03-multiple-data-js.yml +28 -0
  303. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/04-select-integer-boolean.yml +41 -0
  304. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/05-resource-requirements.yml +25 -0
  305. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/06-biocontainer-tool.yml +38 -0
  306. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/07-inline-python-script.yml +56 -0
  307. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/08-configfile-script.yml +74 -0
  308. package/extensions/orbit/vendor/skills/skills/udt-authoring/references/common-mistakes.md +76 -0
  309. package/extensions/orbit/vendor/skills/skills/udt-authoring/references/schema-reference.md +155 -0
  310. package/extensions/orbit/vendor/skills/skills/udt-authoring/references/templating.md +196 -0
  311. package/extensions/orbit/vendor/skills/skills/udt-authoring/scripts/validate.py +109 -0
  312. package/extensions/orbit/vendor/skills/skills/workflow-reports/README.md +71 -0
  313. package/extensions/orbit/vendor/skills/skills/workflow-reports/SKILL.md +190 -0
  314. package/extensions/orbit/vendor/skills/skills/workflow-reports/examples/histology-staining.md +145 -0
  315. package/extensions/orbit/vendor/skills/skills/workflow-reports/examples/tissue-microarray-analysis.md +176 -0
  316. package/extensions/orbit/vendor/skills/skills/workflow-reports/references/directives.md +415 -0
  317. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/SKILL.md +98 -0
  318. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/_provenance.json +93 -0
  319. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/_required_tools.json +28 -0
  320. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/_verify.json +17 -0
  321. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/references/cli/convert.json +123 -0
  322. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/references/cli/foundry.md +25 -0
  323. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/references/cli/validate.json +142 -0
  324. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/references/schemas/summary-galaxy-workflow.schema.json +687 -0
  325. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/SKILL.md +74 -0
  326. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/_provenance.json +71 -0
  327. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/_required_tools.json +16 -0
  328. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/_verify.json +4 -0
  329. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/references/cli/validate.json +142 -0
  330. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/references/notes/galaxy-workflow-invocation-failure-reference.md +138 -0
  331. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/references/notes/galaxy-workflow-testability-design.md +136 -0
  332. package/extensions/orbit/vendor-skills.ts +283 -0
  333. package/extensions/orbit/workspace-state-dir.ts +46 -0
  334. package/extensions/orbit-handoff/index.ts +73 -0
  335. package/extensions/orbit-handoff/orbit-launcher.ts +142 -0
  336. package/extensions/whats-new/index.ts +98 -0
  337. package/lessons/LICENSE +17 -0
  338. package/lessons/README.md +117 -0
  339. package/lessons/SCHEMA.md +187 -0
  340. package/lessons/build-snapshot.mjs +311 -0
  341. package/lessons/data/downloaded-file-is-not-what-its-extension-says.md +61 -0
  342. package/lessons/galaxy-api/403-history-is-a-hard-stop.md +57 -0
  343. package/lessons/galaxy-api/collection-into-single-dataset-input.md +61 -0
  344. package/lessons/galaxy-api/connectedvalue-in-command-line.md +62 -0
  345. package/lessons/galaxy-api/hid-is-not-an-id.md +59 -0
  346. package/lessons/galaxy-api/invoke-workflow-inputs-not-params.md +60 -0
  347. package/lessons/galaxy-api/repeat-param-pipe-keys.md +63 -0
  348. package/lessons/galaxy-api/run-tool-returns-on-submit.md +61 -0
  349. package/lessons/galaxy-tools/reference-index-not-on-server.md +62 -0
  350. package/lessons/log.md +42 -0
  351. package/lessons/reproduction/input-population-mismatch.md +59 -0
  352. package/lessons/reproduction/methods-text-vs-executed-parameters.md +62 -0
  353. package/lessons/snapshot.json +1004 -0
  354. package/lessons/stats/de-contrast-direction-and-sample-labels.md +63 -0
  355. package/lessons/stats/na-coerced-to-zero-in-filters.md +59 -0
  356. package/lessons/validate.mjs +1219 -0
  357. package/package.json +103 -5
  358. package/shared/agent-prompt.d.ts +8 -0
  359. package/shared/agent-prompt.js +15 -0
  360. package/shared/approval-prompt.d.ts +4 -0
  361. package/shared/approval-prompt.js +61 -0
  362. package/shared/brain-env.d.ts +14 -0
  363. package/shared/brain-env.js +108 -0
  364. package/shared/brain-exit.d.ts +20 -0
  365. package/shared/brain-exit.js +149 -0
  366. package/shared/capability-profile.d.ts +16 -0
  367. package/shared/capability-profile.js +75 -0
  368. package/shared/config-source.d.ts +13 -0
  369. package/shared/config-source.js +17 -0
  370. package/shared/confusables.d.ts +3 -0
  371. package/shared/confusables.js +93 -0
  372. package/shared/custom-provider.d.ts +45 -0
  373. package/shared/custom-provider.js +169 -0
  374. package/shared/dashboard-contract.d.ts +123 -0
  375. package/shared/dashboard-contract.js +560 -0
  376. package/shared/dashboard-layout-store.d.ts +44 -0
  377. package/shared/dashboard-layout-store.js +281 -0
  378. package/shared/feedback-contract.d.ts +61 -0
  379. package/shared/feedback-contract.js +146 -0
  380. package/shared/galaxy-artifact-links.d.ts +30 -0
  381. package/shared/galaxy-artifact-links.js +166 -0
  382. package/shared/galaxy-credentials.d.ts +26 -0
  383. package/shared/galaxy-credentials.js +71 -0
  384. package/shared/galaxy-destructive.d.ts +21 -0
  385. package/shared/galaxy-destructive.js +269 -0
  386. package/shared/galaxy-guidance.d.ts +2 -0
  387. package/shared/galaxy-guidance.js +53 -0
  388. package/shared/galaxy-live-contract.d.ts +92 -0
  389. package/shared/galaxy-live-contract.js +180 -0
  390. package/shared/galaxy-page-cells.d.ts +2 -0
  391. package/shared/galaxy-page-cells.js +22 -0
  392. package/shared/galaxy-tool-family.d.ts +5 -0
  393. package/shared/galaxy-tool-family.js +27 -0
  394. package/shared/galaxy-url.d.ts +1 -0
  395. package/shared/galaxy-url.js +48 -0
  396. package/shared/gtn.d.ts +31 -0
  397. package/shared/gtn.js +253 -0
  398. package/shared/handled-prompt.d.ts +3 -0
  399. package/shared/handled-prompt.js +26 -0
  400. package/shared/known-provider.d.ts +11 -0
  401. package/shared/known-provider.js +89 -0
  402. package/shared/lesson-hint-marker.d.ts +7 -0
  403. package/shared/lesson-hint-marker.js +32 -0
  404. package/shared/lesson-rules.d.ts +150 -0
  405. package/shared/lesson-rules.js +203 -0
  406. package/shared/malformed-object-ids.d.ts +1 -0
  407. package/shared/malformed-object-ids.js +37 -0
  408. package/shared/markdown-sections.d.ts +10 -0
  409. package/shared/markdown-sections.js +118 -0
  410. package/shared/notebook-fences.d.ts +12 -0
  411. package/shared/notebook-fences.js +53 -0
  412. package/shared/observation-contract.d.ts +91 -0
  413. package/shared/observation-contract.js +544 -0
  414. package/shared/orbit-config.d.ts +226 -0
  415. package/shared/orbit-config.js +189 -0
  416. package/shared/orbit-env.d.ts +13 -0
  417. package/shared/orbit-env.js +124 -0
  418. package/shared/orbit-shell-contract.d.ts +74 -0
  419. package/shared/orbit-shell-contract.js +30 -0
  420. package/shared/page-content-hash.d.ts +1 -0
  421. package/shared/page-content-hash.js +13 -0
  422. package/shared/pi-default-model.d.ts +7 -0
  423. package/shared/pi-default-model.js +41 -0
  424. package/shared/prompt-blocks.d.ts +87 -0
  425. package/shared/prompt-blocks.js +898 -0
  426. package/shared/provider-auth-caps.d.ts +22 -0
  427. package/shared/provider-auth-caps.js +57 -0
  428. package/shared/random.d.ts +2 -0
  429. package/shared/random.js +15 -0
  430. package/shared/record-excerpt.d.ts +4 -0
  431. package/shared/record-excerpt.js +16 -0
  432. package/shared/redirect-guard.d.ts +36 -0
  433. package/shared/redirect-guard.js +235 -0
  434. package/shared/skills-pin.d.ts +8 -0
  435. package/shared/skills-pin.js +9 -0
  436. package/shared/skills-router.d.ts +17 -0
  437. package/shared/skills-router.js +63 -0
  438. package/shared/sra-import.d.ts +34 -0
  439. package/shared/sra-import.js +206 -0
  440. package/shared/state-dir.d.ts +21 -0
  441. package/shared/state-dir.js +240 -0
  442. package/shared/team-dispatch-contract.d.ts +28 -0
  443. package/shared/team-dispatch-contract.js +1 -0
  444. package/shared/truncate-middle.d.ts +11 -0
  445. package/shared/truncate-middle.js +68 -0
  446. package/shared/version-compare.d.ts +10 -0
  447. package/shared/version-compare.js +74 -0
  448. package/shared/whats-new.d.ts +31 -0
  449. package/shared/whats-new.js +83 -0
  450. package/shared/wsl.d.ts +10 -0
  451. package/shared/wsl.js +24 -0
package/bin/orbit.js ADDED
@@ -0,0 +1,810 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { main } from "@earendil-works/pi-coding-agent";
4
+ import { resolve, dirname, join } from "path";
5
+ import { fileURLToPath, pathToFileURL } from "url";
6
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
7
+ import { homedir } from "os";
8
+ import { loadConfig as loadOrbitConfig } from "../shared/orbit-config.js";
9
+ import { migrateStateDir } from "../shared/state-dir.js";
10
+ import { spawn } from "child_process";
11
+ import { getOrbitVersion, detectInstall } from "./update-check.js";
12
+ import { resolveHideThinking, isInteractiveTerminal } from "./thinking-pref.js";
13
+ import { hasStoredCredential, isProviderUsable, pickSignedInFallback } from "./provider-auth.js";
14
+ import { SEED_OAUTH_ONLY_PROVIDERS } from "../shared/provider-auth-caps.js";
15
+ import { EX_CONFIG } from "../shared/brain-exit.js";
16
+ import { resolvePiExtensionDir } from "./pi-extension-path.js";
17
+ import { migrateLegacyMcpConfig } from "./legacy-mcp-config.js";
18
+ import {
19
+ describeMissingGalaxyCredentials,
20
+ resolveGalaxyCredentials,
21
+ } from "../shared/galaxy-credentials.js";
22
+ import { loadPiDefaultModels, piDefaultModel } from "../shared/pi-default-model.js";
23
+ import {
24
+ isKnownProvider,
25
+ modelsJsonProviders,
26
+ unknownProviderMessage,
27
+ userExtensionsMayRegisterProviders,
28
+ } from "../shared/known-provider.js";
29
+ import { pickChannel } from "../shared/version-compare.js";
30
+ import {
31
+ isCustomProvider,
32
+ syncCustomProviderModelsFile,
33
+ resolveActiveLlmApiKey,
34
+ ENDPOINT_APIS,
35
+ DEFAULT_ENDPOINT_API,
36
+ } from "../shared/custom-provider.js";
37
+ import { isDesktopShell, mirrorToLegacyEnv, readEnv, writeEnv } from "../shared/orbit-env.js";
38
+
39
+ const __dirname = dirname(fileURLToPath(import.meta.url));
40
+
41
+ // Orbit is a standalone product — suppress Pi's branding and update checks.
42
+ // quietStartup hides the keybinding banner + resource listing on launch.
43
+ process.env.PI_SKIP_VERSION_CHECK = "1";
44
+
45
+ // Resolve extension paths relative to this script
46
+ const extensionPath = resolve(__dirname, "../extensions/orbit");
47
+ // CLI-shell hand-off glue (the /desktop command). Kept out of the Orbit core so
48
+ // the brain stays shell-neutral; the command no-ops when embedded in Orbit.
49
+ const orbitHandoffPath = resolve(__dirname, "../extensions/orbit-handoff");
50
+ const cliUpdatePath = resolve(__dirname, "../extensions/cli-update");
51
+ const whatsNewPath = resolve(__dirname, "../extensions/whats-new");
52
+ const updateCheckScript = resolve(__dirname, "update-check.js");
53
+
54
+ // pi-web-access provides web_search, fetch_content, and code_search tools
55
+ import { createRequire } from "module";
56
+ const require = createRequire(import.meta.url);
57
+ const resolveSpecifier = (specifier) => require.resolve(specifier);
58
+ const webAccessPath = resolvePiExtensionDir("pi-web-access", resolveSpecifier);
59
+ const piEntryPointPath = fileURLToPath(import.meta.resolve("@earendil-works/pi-coding-agent"));
60
+ const piPackageDir = dirname(dirname(piEntryPointPath));
61
+ const piArgsModulePath = join(piPackageDir, "dist/cli/args.js");
62
+ const piListModelsModulePath = join(piPackageDir, "dist/cli/list-models.js");
63
+ const piConfigModulePath = join(piPackageDir, "dist/config.js");
64
+ const piModelRuntimeModulePath = join(piPackageDir, "dist/core/model-runtime.js");
65
+ const userArgs = process.argv.slice(2);
66
+
67
+ // pi resolves a custom provider's key from LOOM_ACTIVE_LLM_API_KEY by name, so
68
+ // a key supplied only as ORBIT_ACTIVE_LLM_API_KEY needs the legacy twin.
69
+ mirrorToLegacyEnv(process.env, "ACTIVE_LLM_API_KEY");
70
+
71
+ // Local-execution safety flags. Translate to env so the exec-guard (brain side)
72
+ // reads them; strip so they aren't forwarded to pi as unknown flags.
73
+ if (userArgs.includes("--dangerously-bypass-permissions")) {
74
+ writeEnv(process.env, "DANGEROUSLY_BYPASS_PERMISSIONS", "1");
75
+ }
76
+ if (userArgs.includes("--safe")) {
77
+ writeEnv(process.env, "SAFE", "1");
78
+ }
79
+ // Opt-in bash sandbox: run allowed bash inside an OS sandbox (the gate still gates).
80
+ if (userArgs.includes("--sandbox")) {
81
+ writeEnv(process.env, "SANDBOX", "1");
82
+ }
83
+ // A bare interactive CLI always has a local execution surface, so the exec-guard
84
+ // (brain side) must stay on regardless of any ambient LOOM_LOCAL_EXEC in the
85
+ // launching env. The web/desktop shells run the brain with --mode rpc and set
86
+ // LOOM_LOCAL_EXEC authoritatively themselves (off for the no-exec web container,
87
+ // on for desktop), so only pin it here for the non-rpc CLI path.
88
+ const isRpcMode = userArgs.includes("--mode") && userArgs[userArgs.indexOf("--mode") + 1] === "rpc";
89
+ if (!isRpcMode) {
90
+ writeEnv(process.env, "LOCAL_EXEC", "on");
91
+ }
92
+ if (userArgs.includes("--no-update-check")) {
93
+ writeEnv(process.env, "NO_UPDATE_CHECK", "1");
94
+ }
95
+ for (let i = userArgs.length - 1; i >= 0; i--) {
96
+ if (
97
+ userArgs[i] === "--dangerously-bypass-permissions" ||
98
+ userArgs[i] === "--safe" ||
99
+ userArgs[i] === "--sandbox" ||
100
+ userArgs[i] === "--no-update-check"
101
+ ) {
102
+ userArgs.splice(i, 1);
103
+ }
104
+ }
105
+
106
+ function hasArg(flag) {
107
+ return userArgs.includes(flag) || userArgs.some((arg) => arg.startsWith(`${flag}=`));
108
+ }
109
+
110
+ const isInformationalCommand = ["--help", "-h", "--version", "--list-models"].some(hasArg);
111
+
112
+ // Before the first config read, so a fresh copy in ~/.orbit is what gets read.
113
+ const migration = migrateStateDir();
114
+ if (migration.status === "failed") {
115
+ const why = migration.error instanceof Error ? migration.error.message : String(migration.error);
116
+ console.error(
117
+ `orbit: could not copy ~/.loom to ~/.orbit (${why}); still reading ~/.loom/config.json.`,
118
+ );
119
+ }
120
+
121
+ // Config opt-out feeds the same single signal the extension + refresh read.
122
+ try {
123
+ if (loadOrbitConfig().updateCheck === false) writeEnv(process.env, "NO_UPDATE_CHECK", "1");
124
+ } catch {}
125
+
126
+ if (
127
+ !isInformationalCommand &&
128
+ readEnv("DANGEROUSLY_BYPASS_PERMISSIONS") === "1" &&
129
+ readEnv("SAFE") !== "1"
130
+ ) {
131
+ console.error(
132
+ "\n \x1b[1;31m⚠ PERMISSIONS BYPASSED\x1b[0m -- Orbit will run any command without asking.\n",
133
+ );
134
+ }
135
+
136
+ function getListModelsSearchPattern() {
137
+ const index = userArgs.findIndex((arg) => arg === "--list-models");
138
+ if (index === -1) return undefined;
139
+ const candidate = userArgs[index + 1];
140
+ if (!candidate || candidate.startsWith("-") || candidate.startsWith("@")) {
141
+ return undefined;
142
+ }
143
+ return candidate;
144
+ }
145
+
146
+ async function handleInformationalCommand() {
147
+ if (hasArg("--help") || hasArg("-h")) {
148
+ const { printHelp } = await import(pathToFileURL(piArgsModulePath).href);
149
+ printHelp();
150
+ return true;
151
+ }
152
+
153
+ if (hasArg("--version")) {
154
+ const { VERSION } = await import(pathToFileURL(piConfigModulePath).href);
155
+ console.log(`orbit ${getOrbitVersion()} (pi-coding-agent ${VERSION})`);
156
+ return true;
157
+ }
158
+
159
+ if (hasArg("--list-models")) {
160
+ const { listModels } = await import(pathToFileURL(piListModelsModulePath).href);
161
+ const { getModelsPath } = await import(pathToFileURL(piConfigModulePath).href);
162
+ // pi 0.83 reshaped this: listModels now takes a ModelRuntime (built via an
163
+ // async factory that reads credentials from authPath itself) rather than a
164
+ // ModelRegistry wrapped around an AuthStorage.
165
+ const { ModelRuntime } = await import(pathToFileURL(piModelRuntimeModulePath).href);
166
+ const modelRuntime = await ModelRuntime.create({ modelsPath: getModelsPath() });
167
+ await listModels(modelRuntime, getListModelsSearchPattern());
168
+ return true;
169
+ }
170
+
171
+ return false;
172
+ }
173
+
174
+ // ─────────────────────────────────────────────────────────────────────────────
175
+ // Orbit brain-level config (<state dir>/config.json, see shared/state-dir.js)
176
+ //
177
+ // Shared by every consumer (Orbit CLI, Orbit, future shells). The CLI only
178
+ // reads/writes it; it doesn't own the schema. Shell-specific state lives in
179
+ // each shell's own dir.
180
+ // ─────────────────────────────────────────────────────────────────────────────
181
+
182
+ const agentDir = process.env.PI_CODING_AGENT_DIR || join(homedir(), ".pi", "agent");
183
+
184
+ // ─────────────────────────────────────────────────────────────────────────────
185
+ // Apply consolidated config
186
+ // ─────────────────────────────────────────────────────────────────────────────
187
+
188
+ const orbitConfig = loadOrbitConfig();
189
+
190
+ // Provider name → env var mapping
191
+ const PROVIDER_ENV_MAP = {
192
+ anthropic: "ANTHROPIC_API_KEY",
193
+ openai: "OPENAI_API_KEY",
194
+ google: "GEMINI_API_KEY",
195
+ mistral: "MISTRAL_API_KEY",
196
+ groq: "GROQ_API_KEY",
197
+ xai: "XAI_API_KEY",
198
+ deepseek: "DEEPSEEK_API_KEY",
199
+ };
200
+
201
+ // Providers that authenticate ONLY by sign-in (~/.pi/agent/auth.json), with no
202
+ // API-key path at all. Deliberately NOT "every provider that offers sign-in":
203
+ // anthropic, xai, openrouter and friends carry both, and treating them as
204
+ // sign-in-only is exactly the conflation that caused #429 on the Orbit side.
205
+ // The CLI has no pi registry to read, so it answers from the same seed Orbit
206
+ // falls back to before its own registry read lands.
207
+ const OAUTH_ONLY_PROVIDERS = new Set(SEED_OAUTH_ONLY_PROVIDERS);
208
+
209
+ function readAuthJson() {
210
+ const authPath = join(agentDir, "auth.json");
211
+ if (!existsSync(authPath)) return {};
212
+ try {
213
+ return JSON.parse(readFileSync(authPath, "utf-8")) || {};
214
+ } catch {
215
+ return {};
216
+ }
217
+ }
218
+
219
+ // Can this CLI actually authenticate the given provider? A stored auth.json
220
+ // credential counts for any provider; otherwise it needs a plaintext config key
221
+ // or its env var (encrypted config keys aren't decryptable outside Orbit).
222
+ // Custom OpenAI-compatible providers resolve their key from the injected env var
223
+ // (Orbit) or a plaintext config key (CLI) -- same logic as checkLLMProvider.
224
+ function activeProviderUsable(provider, entry, auth) {
225
+ return isProviderUsable(provider, entry, auth, {
226
+ env: process.env,
227
+ oauthOnlyProviders: OAUTH_ONLY_PROVIDERS,
228
+ providerEnvMap: PROVIDER_ENV_MAP,
229
+ customKeyResolved: isCustomProvider(entry)
230
+ ? resolveActiveLlmApiKey(entry, process.env)
231
+ : undefined,
232
+ });
233
+ }
234
+
235
+ // Pi's `/login` writes credentials to auth.json but never touches Orbit's
236
+ // llm.active, so signing into a new provider mid-session has no effect on the
237
+ // next launch. Bridge that gap for the standalone CLI: if the configured active
238
+ // provider has no credential we can use, fall back to one that's signed in.
239
+ //
240
+ // In memory only. This used to persist, which made a subprocess the last writer
241
+ // of a setting the user owns -- an Orbit prefs save could be silently undone by
242
+ // the very restart it triggered (#429). Nothing is lost by not writing: the next
243
+ // launch re-derives the same answer from the same two files.
244
+ function reconcileActiveProviderWithAuth() {
245
+ // Shell-owned sessions (Orbit, web) choose the provider themselves and hand us
246
+ // credentials by env -- a child process must not overrule that. And an
247
+ // informational command must never touch provider state at all.
248
+ if (isRpcMode || isInformationalCommand) return;
249
+ const llm = orbitConfig.llm;
250
+ if (!llm?.active) return;
251
+ const auth = readAuthJson();
252
+ if (activeProviderUsable(llm.active, llm.providers?.[llm.active], auth)) return;
253
+ const candidate = pickSignedInFallback(auth, OAUTH_ONLY_PROVIDERS, llm.active);
254
+ if (!candidate) return;
255
+ const from = llm.active;
256
+ llm.active = candidate;
257
+ llm.providers = llm.providers || {};
258
+ if (!llm.providers[candidate]) llm.providers[candidate] = {};
259
+ console.error(
260
+ `orbit: active provider "${from}" has no usable credential here; using "${candidate}" for this run (signed in via ~/.pi/agent/auth.json). Set it permanently in Orbit's Preferences, or add a key for "${from}".`,
261
+ );
262
+ }
263
+ reconcileActiveProviderWithAuth();
264
+
265
+ // apiKeyEncrypted isn't readable here -- no Electron safeStorage in the
266
+ // brain process. Orbit decrypts and passes via env when it spawns us;
267
+ // standalone CLI usage only works with plaintext keys. OAuth providers
268
+ // skip env injection entirely: a stale apiKey on the entry shouldn't leak
269
+ // under a misrouted env variable when the brain will authenticate via
270
+ // ~/.pi/agent/auth.json anyway.
271
+ const activeLlmProvider = orbitConfig.llm?.active;
272
+ const activeLlmConfig = activeLlmProvider ? orbitConfig.llm?.providers?.[activeLlmProvider] : null;
273
+ if (
274
+ activeLlmConfig?.apiKey &&
275
+ !OAUTH_ONLY_PROVIDERS.has(activeLlmProvider) &&
276
+ !isCustomProvider(activeLlmConfig)
277
+ ) {
278
+ const envVar = PROVIDER_ENV_MAP[activeLlmProvider] || "AI_GATEWAY_API_KEY";
279
+ if (!process.env[envVar]) {
280
+ process.env[envVar] = activeLlmConfig.apiKey;
281
+ }
282
+ }
283
+
284
+ // Custom endpoint: register it in ~/.pi/agent/models.json so pi can resolve
285
+ // --provider/--model. The key is NOT written here; it's supplied at runtime via
286
+ // --api-key below.
287
+ if (!isInformationalCommand && activeLlmProvider && isCustomProvider(activeLlmConfig)) {
288
+ try {
289
+ syncCustomProviderModelsFile(join(agentDir, "models.json"), activeLlmProvider, activeLlmConfig);
290
+ } catch (err) {
291
+ // A rejected `api` is a config problem the user has to fix, not a transient
292
+ // one: limping on would leave models.json without the provider and surface
293
+ // as an unexplained "--provider/--model failed to resolve" from pi. Exit
294
+ // EX_CONFIG so a shell shows this message instead of retrying (#439).
295
+ if (err instanceof Error && err.message.startsWith("unsupported endpoint api")) {
296
+ console.error(`orbit: provider "${activeLlmProvider}" -- ${err.message}.
297
+
298
+ Set "llm.providers.${activeLlmProvider}.api" in ~/.orbit/config.json to one of
299
+ ${ENDPOINT_APIS.join(" / ")}, or remove it to use ${DEFAULT_ENDPOINT_API}.
300
+ `);
301
+ process.exit(EX_CONFIG);
302
+ }
303
+ console.error(`orbit: failed to sync custom provider into models.json: ${err}`);
304
+ }
305
+ }
306
+
307
+ // Prefer auth.json (OAuth) over a stray provider env key. When the active
308
+ // provider authenticates via OAuth and is signed in, scrub the conflicting
309
+ // *_API_KEY from the env so Pi uses the OAuth token -- otherwise a leftover
310
+ // (possibly dummy) key like OPENAI_API_KEY shadows it and routes the request
311
+ // to the keyed provider with the wrong credential. Mirrors the Galaxy-cred
312
+ // scrubbing below.
313
+ const OAUTH_CONFLICT_ENV = {
314
+ "openai-codex": ["OPENAI_API_KEY"],
315
+ };
316
+ if (activeLlmProvider && OAUTH_ONLY_PROVIDERS.has(activeLlmProvider)) {
317
+ const auth = readAuthJson();
318
+ if (hasStoredCredential(auth, activeLlmProvider)) {
319
+ for (const v of OAUTH_CONFLICT_ENV[activeLlmProvider] || []) {
320
+ if (process.env[v]) delete process.env[v];
321
+ }
322
+ }
323
+ }
324
+
325
+ // ─────────────────────────────────────────────────────────────────────────────
326
+ // Galaxy credentials
327
+ //
328
+ // Credentials come from an exported GALAXY_URL + GALAXY_API_KEY pair, else
329
+ // the active profile in config.json (written by /connect). The pair wins so
330
+ // any server is one env prefix away; shells pass their chosen server the same
331
+ // way. The in-process Galaxy tools are always registered; the agent decides
332
+ // per-plan whether to use Galaxy. The `executionMode` field affects prompt
333
+ // guidance, not which tools are registered.
334
+ // ─────────────────────────────────────────────────────────────────────────────
335
+
336
+ const galaxyCredentials = resolveGalaxyCredentials({
337
+ config: orbitConfig,
338
+ env: process.env,
339
+ prefer: "env",
340
+ });
341
+ const galaxyUrl = galaxyCredentials?.url ?? null;
342
+ const galaxyApiKey = galaxyCredentials?.apiKey ?? null;
343
+ // A half-set env pair is worth a word even when the saved profile still works.
344
+ if (galaxyCredentials?.source !== "env" && !isInformationalCommand && !isDesktopShell()) {
345
+ const why = describeMissingGalaxyCredentials({ config: orbitConfig, env: process.env });
346
+ if (why) console.error(`[orbit] ${why}`);
347
+ }
348
+
349
+ // Publish to env so the extension can read them. If credentials are absent,
350
+ // scrub stale env so the extension doesn't see ghosts from a prior session.
351
+ if (galaxyUrl && galaxyApiKey) {
352
+ process.env.GALAXY_URL = galaxyUrl;
353
+ process.env.GALAXY_API_KEY = galaxyApiKey;
354
+ } else {
355
+ delete process.env.GALAXY_URL;
356
+ delete process.env.GALAXY_API_KEY;
357
+ }
358
+
359
+ // The brain registers Orbit's MCP servers itself (extensions/orbit/mcp-servers.ts);
360
+ // clear out what earlier versions left in mcp.json.
361
+ // A copy of the old file lands beside it first, and a file that cannot be
362
+ // updated is reported rather than fatal (bin/legacy-mcp-config.js says why).
363
+ if (!isInformationalCommand) {
364
+ const { notices } = migrateLegacyMcpConfig(join(agentDir, "mcp.json"));
365
+ for (const notice of notices) console.error(`[orbit] ${notice}`);
366
+ }
367
+
368
+ // ─────────────────────────────────────────────────────────────────────────────
369
+ // pi-web-access defaults: skip the curator browser popup, drop source_check.
370
+ //
371
+ // pi-web-access ships with the brain and exposes a web_search tool. Its
372
+ // default workflow ("summary-review") opens a curator window in the system
373
+ // browser on every search so the user can prune results before the LLM sees
374
+ // them. In Orbit the chat is the UI, so popping a separate browser tab on
375
+ // every search is jarring -- and on a fresh install with no Exa/Gemini key,
376
+ // the search still routes through Exa MCP (https://mcp.exa.ai/mcp, no auth)
377
+ // so the popup is the only thing standing between the user and a working
378
+ // zero-config web search. Default workflow:"none" returns raw results inline
379
+ // for the LLM to summarize. Users who want the curator back can flip it on
380
+ // with `/curator on` or by setting "workflow":"summary-review" in this file.
381
+ // ─────────────────────────────────────────────────────────────────────────────
382
+
383
+ // Mirrors pi-web-access's own lookup (utils.ts getWebSearchConfigDir). It
384
+ // prefers ~/.pi/agent over the legacy ~/.pi, so writing a fixed path would
385
+ // leave our defaults in a file it never reads.
386
+ function resolveWebSearchConfigPath() {
387
+ const file = "web-search.json";
388
+ if (process.env.PI_CODING_AGENT_DIR) return join(process.env.PI_CODING_AGENT_DIR, file);
389
+ const legacyDir = join(homedir(), ".pi");
390
+ const xdgConfigHome = process.env.XDG_CONFIG_HOME;
391
+ const preferredDir = xdgConfigHome ? join(xdgConfigHome, "pi") : join(homedir(), ".pi", "agent");
392
+ for (const dir of [preferredDir, legacyDir]) {
393
+ if (existsSync(join(dir, file))) return join(dir, file);
394
+ }
395
+ // Neither exists yet: keep writing the legacy path, which pi-web-access
396
+ // picks up as long as nothing is at the preferred one.
397
+ return join(legacyDir, file);
398
+ }
399
+
400
+ const webSearchConfigPath = resolveWebSearchConfigPath();
401
+
402
+ if (!isInformationalCommand) {
403
+ let webSearchConfig = {};
404
+ let parseOk = true;
405
+ if (existsSync(webSearchConfigPath)) {
406
+ try {
407
+ webSearchConfig = JSON.parse(readFileSync(webSearchConfigPath, "utf-8"));
408
+ } catch {
409
+ // Don't clobber a file we can't parse -- pi-web-access surfaces a
410
+ // more useful error on its own when it tries to load this.
411
+ parseOk = false;
412
+ }
413
+ }
414
+ if (parseOk && webSearchConfig && typeof webSearchConfig === "object") {
415
+ let changed = false;
416
+ if (webSearchConfig.workflow === undefined) {
417
+ webSearchConfig.workflow = "none";
418
+ changed = true;
419
+ }
420
+ // source_check (claim verification against retrieved passages) is rarely
421
+ // what an analysis needs and its schema costs ~600 tokens on every
422
+ // request. Off unless the user has set it either way.
423
+ const tools = webSearchConfig.tools;
424
+ const toolsOk =
425
+ tools === undefined || (tools && typeof tools === "object" && !Array.isArray(tools));
426
+ if (toolsOk && tools?.sourceCheck?.enabled === undefined) {
427
+ webSearchConfig.tools = {
428
+ ...tools,
429
+ sourceCheck: { ...tools?.sourceCheck, enabled: false },
430
+ };
431
+ changed = true;
432
+ }
433
+ if (changed) {
434
+ mkdirSync(dirname(webSearchConfigPath), { recursive: true });
435
+ writeFileSync(webSearchConfigPath, JSON.stringify(webSearchConfig, null, 2));
436
+ }
437
+ }
438
+ }
439
+
440
+ // ─────────────────────────────────────────────────────────────────────────────
441
+ // Pre-flight: ensure at least one LLM provider is configured
442
+ // ─────────────────────────────────────────────────────────────────────────────
443
+
444
+ /**
445
+ * Where to go to fix a missing credential, phrased for the shell we're running
446
+ * under. The CLI wording ("Launch via Orbit and sign in from Preferences") is
447
+ * actively wrong inside Orbit -- it points at the app the user is already
448
+ * looking at, which is the half of #429 that survived the first fix. Route every
449
+ * exit below through here so a new one can't quietly regress to CLI-only advice.
450
+ */
451
+ function credentialFixHint(provider, { canUseApiKey }) {
452
+ if (isRpcMode) {
453
+ return canUseApiKey
454
+ ? `Open Preferences, re-enter the API key for "${provider}" or sign in to it,
455
+ then start a new session.`
456
+ : `Open Preferences, sign in to "${provider}", then start a new session.`;
457
+ }
458
+ if (!canUseApiKey) {
459
+ return `Launch the Orbit desktop app and sign in from Preferences,
460
+ or unset "llm.active" in ~/.orbit/config.json.`;
461
+ }
462
+ const envVar = PROVIDER_ENV_MAP[provider] || "AI_GATEWAY_API_KEY";
463
+ return `Do one of the following:
464
+
465
+ * Export the key for this shell:
466
+ export ${envVar}=...
467
+
468
+ * Launch the Orbit desktop app, which decrypts the stored key
469
+ and injects ${envVar} into the brain.
470
+
471
+ * Unset "llm.active" in ~/.orbit/config.json.`;
472
+ }
473
+
474
+ /**
475
+ * A saved provider pi no longer ships (ollama after pi 1.1.0, #598) makes pi
476
+ * exit 1 on startup, which Orbit retries until its budget runs out. Catch it
477
+ * here so it exits EX_CONFIG with a message the shell can show.
478
+ */
479
+ async function checkProviderKnown() {
480
+ const skipFlags = ["--version", "--help", "-h", "--list-models"];
481
+ if (userArgs.some((a) => skipFlags.some((f) => a.startsWith(f)))) return;
482
+ // Only the provider we inject is ours to vouch for.
483
+ if (hasArg("--provider") || hasArg("--models")) return;
484
+ if (!activeLlmProvider || isCustomProvider(activeLlmConfig)) return;
485
+ if (userExtensionsMayRegisterProviders(agentDir, process.cwd())) return;
486
+ let builtIn;
487
+ try {
488
+ ({ getProviders: builtIn } = await import("@earendil-works/pi-ai/compat"));
489
+ } catch {
490
+ // Can't see pi's registry -- leave the verdict to pi.
491
+ return;
492
+ }
493
+ const extra = modelsJsonProviders(join(agentDir, "models.json"));
494
+ if (isKnownProvider(activeLlmProvider, builtIn(), extra)) return;
495
+ console.error(unknownProviderMessage(activeLlmProvider));
496
+ process.exit(EX_CONFIG);
497
+ }
498
+
499
+ /**
500
+ * Every exit below is EX_CONFIG, not 1: each one has already diagnosed the
501
+ * problem and printed the fix for it, and none of them can come out differently
502
+ * on a second attempt. A shell reads that code as "show this, don't retry"
503
+ * (#439) -- under the old blanket 1, Orbit restarted three times and replaced
504
+ * these messages with a generic crash box.
505
+ */
506
+ function checkLLMProvider() {
507
+ const skipFlags = ["--version", "--help", "-h", "--api-key", "--list-models"];
508
+ if (userArgs.some((a) => skipFlags.some((f) => a.startsWith(f)))) return;
509
+ if (hasArg("--provider")) return;
510
+
511
+ // pi reads ~/.pi/agent/auth.json natively, so a stored login authenticates the
512
+ // active provider on its own. This has to come before every key path below:
513
+ // a dual-auth provider the user IS signed in to would otherwise hit the
514
+ // encrypted-key exit and die over a key it never needed (#429), which also
515
+ // contradicts what isProviderUsable() tells the reconciler.
516
+ if (activeLlmProvider && hasStoredCredential(readAuthJson(), activeLlmProvider)) return;
517
+
518
+ // Sign-in-only providers have no key path at all, so with no stored login
519
+ // there is nothing left to try. Stale plaintext / encrypted fields on the
520
+ // entry are ignored entirely so they can't mask the missing sign-in or
521
+ // falsely trigger the encrypted-key exit below.
522
+ if (activeLlmProvider && OAUTH_ONLY_PROVIDERS.has(activeLlmProvider)) {
523
+ console.error(`orbit: provider "${activeLlmProvider}" requires a sign-in.
524
+
525
+ ${credentialFixHint(activeLlmProvider, { canUseApiKey: false })}
526
+ `);
527
+ process.exit(EX_CONFIG);
528
+ }
529
+
530
+ // Custom OpenAI-compatible provider: usable when a key is resolvable from the
531
+ // injected env var (Orbit) or a plaintext config key (standalone CLI), or
532
+ // when none is stored because the endpoint needs none (#600).
533
+ if (isCustomProvider(activeLlmConfig) && resolveActiveLlmApiKey(activeLlmConfig, process.env)) {
534
+ return;
535
+ }
536
+
537
+ // Consolidated config has an API key (non-OAuth providers only)
538
+ if (activeLlmConfig?.apiKey) return;
539
+
540
+ const providerEnvVars = [
541
+ "ANTHROPIC_API_KEY",
542
+ "ANTHROPIC_OAUTH_TOKEN",
543
+ "OPENAI_API_KEY",
544
+ "GEMINI_API_KEY",
545
+ "GROQ_API_KEY",
546
+ "MISTRAL_API_KEY",
547
+ "XAI_API_KEY",
548
+ "DEEPSEEK_API_KEY",
549
+ "OPENROUTER_API_KEY",
550
+ "CEREBRAS_API_KEY",
551
+ "AI_GATEWAY_API_KEY",
552
+ "HF_TOKEN",
553
+ "AWS_PROFILE",
554
+ "AWS_ACCESS_KEY_ID",
555
+ "GOOGLE_CLOUD_PROJECT",
556
+ "AZURE_OPENAI_API_KEY",
557
+ "COPILOT_GITHUB_TOKEN",
558
+ "GH_TOKEN",
559
+ "GITHUB_TOKEN",
560
+ ];
561
+ if (providerEnvVars.some((v) => process.env[v])) return;
562
+
563
+ // Config has an encrypted key but this process can't decrypt it -- Electron's
564
+ // safeStorage lives in the Orbit main process. Say so instead of falling
565
+ // through to the generic error.
566
+ if (activeLlmConfig?.apiKeyEncrypted) {
567
+ console.error(`orbit: the API key stored for provider "${activeLlmProvider}" could not be
568
+ decrypted here, so no credential reached the agent. (apiKeyEncrypted in
569
+ ~/.orbit/config.json only decrypts inside Orbit.)
570
+
571
+ ${credentialFixHint(activeLlmProvider, { canUseApiKey: true })}
572
+ `);
573
+ process.exit(EX_CONFIG);
574
+ }
575
+
576
+ // Any stored pi login at all -- the user may have signed in via `--provider`
577
+ // without ever setting llm.active.
578
+ if (Object.keys(readAuthJson()).length > 0) return;
579
+
580
+ const modelsPath = join(agentDir, "models.json");
581
+ if (existsSync(modelsPath)) {
582
+ try {
583
+ const models = JSON.parse(readFileSync(modelsPath, "utf-8"));
584
+ const providers = models.providers || {};
585
+ if (Object.values(providers).some((p) => p.apiKey)) return;
586
+ } catch {}
587
+ }
588
+
589
+ if (isRpcMode) {
590
+ console.error(`orbit: no LLM provider is configured, so the agent has no credential.
591
+
592
+ Open Preferences, pick a provider and add its API key (or sign in to it),
593
+ then start a new session.
594
+ `);
595
+ process.exit(EX_CONFIG);
596
+ }
597
+
598
+ console.error(`orbit requires an LLM provider to function.
599
+
600
+ Set up one of the following:
601
+
602
+ 1. Config file (recommended):
603
+ Create ~/.orbit/config.json:
604
+ {
605
+ "llm": {
606
+ "active": "anthropic",
607
+ "providers": {
608
+ "anthropic": { "apiKey": "sk-ant-..." }
609
+ }
610
+ }
611
+ }
612
+
613
+ 2. Environment variable:
614
+ export ANTHROPIC_API_KEY=sk-ant-...
615
+ export OPENAI_API_KEY=sk-...
616
+
617
+ 3. Custom provider (~/.pi/agent/models.json):
618
+ For local/self-hosted models via litellm, ollama, etc.
619
+ See: https://github.com/galaxyproject/orbit#local-llms
620
+
621
+ 4. OAuth login:
622
+ Run with --provider anthropic (or openai, google, etc.)
623
+ and follow the login prompts.
624
+ `);
625
+ process.exit(EX_CONFIG);
626
+ }
627
+
628
+ // ─────────────────────────────────────────────────────────────────────────────
629
+ // Inject --provider / --model from consolidated config or legacy models.json
630
+ // ─────────────────────────────────────────────────────────────────────────────
631
+
632
+ const providerArgs = [];
633
+ if (!hasArg("--provider")) {
634
+ // Prefer consolidated config (multi-provider shape)
635
+ if (activeLlmProvider) {
636
+ // A user's --models picks the model itself, and pi 1.0 refuses --provider
637
+ // alongside it without a --model.
638
+ if (!hasArg("--models")) {
639
+ providerArgs.push("--provider", activeLlmProvider);
640
+ if (!hasArg("--model")) {
641
+ // A provider saved with a key but no model gets pi's own default for it.
642
+ const model =
643
+ activeLlmConfig?.model ?? piDefaultModel(activeLlmProvider, await loadPiDefaultModels());
644
+ if (model) providerArgs.push("--model", model);
645
+ }
646
+ }
647
+ // Custom endpoints have no built-in key resolution; hand pi the key at
648
+ // runtime so it stays in memory (setRuntimeApiKey) rather than on disk.
649
+ if (isCustomProvider(activeLlmConfig) && !hasArg("--api-key")) {
650
+ const key = resolveActiveLlmApiKey(activeLlmConfig, process.env);
651
+ if (key) providerArgs.push("--api-key", key);
652
+ }
653
+ } else {
654
+ // Fall back to legacy models.json
655
+ const modelsPath = join(agentDir, "models.json");
656
+ if (existsSync(modelsPath)) {
657
+ try {
658
+ const models = JSON.parse(readFileSync(modelsPath, "utf-8"));
659
+ const providers = models.providers || {};
660
+ const [providerName, providerConfig] = Object.entries(providers)[0] || [];
661
+ if (providerName && providerConfig?.models?.length) {
662
+ providerArgs.push("--provider", providerName);
663
+ if (!userArgs.includes("--model") && !userArgs.some((a) => a.startsWith("--model="))) {
664
+ providerArgs.push("--model", providerConfig.models[0].id);
665
+ }
666
+ }
667
+ } catch {}
668
+ }
669
+ }
670
+ }
671
+
672
+ // Build args: inject extensions, pass through everything else
673
+ const args = [
674
+ "-e",
675
+ webAccessPath,
676
+ "-e",
677
+ extensionPath,
678
+ "-e",
679
+ orbitHandoffPath,
680
+ "-e",
681
+ cliUpdatePath,
682
+ "-e",
683
+ whatsNewPath,
684
+ ...providerArgs,
685
+ ...userArgs,
686
+ ];
687
+ if (await handleInformationalCommand()) {
688
+ process.exit(0);
689
+ }
690
+
691
+ if (userArgs[0] === "update") {
692
+ if (isDesktopShell()) {
693
+ console.error("Orbit manages its own updates -- update from the Orbit app, not the CLI.");
694
+ process.exit(0);
695
+ }
696
+ const channel = pickChannel(getOrbitVersion());
697
+ const { kind, cmd } = detectInstall(channel);
698
+ if (!cmd) {
699
+ console.error(
700
+ `Orbit looks like a source checkout, not an npm install -- can't self-update.\n` +
701
+ `To upgrade an installed copy: npm install -g @galaxyproject/orbit@${channel}`,
702
+ );
703
+ process.exit(0);
704
+ }
705
+ console.error(`Updating Orbit (${kind}) -- ${cmd}`);
706
+ const [bin, ...rest] = cmd.split(" ");
707
+ const child = spawn(bin, rest, { stdio: "inherit" });
708
+ child.on("error", (err) => {
709
+ console.error(`Failed to run "${cmd}": ${err.message}`);
710
+ process.exit(1);
711
+ });
712
+ child.on("exit", (code) => process.exit(code ?? 0));
713
+ } else {
714
+ await checkProviderKnown();
715
+ checkLLMProvider();
716
+
717
+ // Resolve pi-coding-agent's own version by walking up from its entry point to
718
+ // the package root. Used to pin the changelog watermark below.
719
+ function resolvePiVersion() {
720
+ let dir = dirname(piEntryPointPath);
721
+ for (let i = 0; i < 6; i++) {
722
+ const pkgPath = join(dir, "package.json");
723
+ if (existsSync(pkgPath)) {
724
+ try {
725
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
726
+ if (pkg.name === "@earendil-works/pi-coding-agent") return pkg.version;
727
+ } catch {}
728
+ }
729
+ const parent = dirname(dir);
730
+ if (parent === dir) break;
731
+ dir = parent;
732
+ }
733
+ return null;
734
+ }
735
+
736
+ // Reconcile the Pi settings Orbit manages. Two concerns share one read/write:
737
+ // - Startup quiet (banner, resource listing, "What's New" changelog): Orbit is
738
+ // the product identity, so users shouldn't see Pi internals unless they
739
+ // pass --verbose. The changelog is gated on lastChangelogVersion; pinning
740
+ // it to Pi's current version means getNewEntries() finds nothing newer.
741
+ // - Thinking visibility (interactive terminal only): Pi streams the model's
742
+ // reasoning into the TUI, which is noisy, so Orbit hides it by default.
743
+ // `hideThinkingBlock` is a persisted global Pi setting that only the
744
+ // interactive renderer reads, so only reconcile it for an interactive
745
+ // terminal launch -- never for the non-interactive modes (rpc for Orbit
746
+ // and the web server, json for evals, headless --print), which would
747
+ // churn the global file for a setting they never read. Override
748
+ // persistently with `ui.showThinking: true` in ~/.orbit/config.json, or
749
+ // just toggle it live in-session with Ctrl+T.
750
+ // - TUI mode (interactive terminal only): see below.
751
+ {
752
+ const piSettingsPath = join(agentDir, "settings.json");
753
+ try {
754
+ let piSettings = {};
755
+ if (existsSync(piSettingsPath)) {
756
+ piSettings = JSON.parse(readFileSync(piSettingsPath, "utf-8"));
757
+ }
758
+ let changed = false;
759
+
760
+ if (!hasArg("--verbose")) {
761
+ if (!piSettings.quietStartup) {
762
+ piSettings.quietStartup = true;
763
+ changed = true;
764
+ }
765
+ const piVersion = resolvePiVersion();
766
+ if (piVersion && piSettings.lastChangelogVersion !== piVersion) {
767
+ piSettings.lastChangelogVersion = piVersion;
768
+ changed = true;
769
+ }
770
+ }
771
+
772
+ if (isInteractiveTerminal(userArgs)) {
773
+ const hideThinking = resolveHideThinking({
774
+ configShowThinking: orbitConfig.ui?.showThinking,
775
+ });
776
+ if (piSettings.hideThinkingBlock !== hideThinking) {
777
+ piSettings.hideThinkingBlock = hideThinking;
778
+ changed = true;
779
+ }
780
+ // pi 1.0 went fullscreen by default, which takes away the terminal's own
781
+ // scrollback. Keep Orbit's terminal where it was; only fill the gap, so a
782
+ // user who picks fullscreen in /settings keeps it.
783
+ if (piSettings.tuiMode === undefined) {
784
+ piSettings.tuiMode = "regular";
785
+ changed = true;
786
+ }
787
+ }
788
+
789
+ if (changed) {
790
+ mkdirSync(dirname(piSettingsPath), { recursive: true });
791
+ writeFileSync(piSettingsPath, JSON.stringify(piSettings, null, 2));
792
+ }
793
+ } catch {}
794
+ }
795
+
796
+ // Refresh the update-check cache in a fully detached child so the network call
797
+ // never delays startup, holds the TUI, or is killed mid-write. The notice the
798
+ // user sees this run comes from the cache; this updates it for next run.
799
+ if (!isDesktopShell() && readEnv("NO_UPDATE_CHECK") !== "1") {
800
+ try {
801
+ const refresh = spawn(process.execPath, [updateCheckScript, "--refresh"], {
802
+ detached: true,
803
+ stdio: "ignore",
804
+ });
805
+ refresh.unref();
806
+ } catch {}
807
+ }
808
+
809
+ main(args);
810
+ }