@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
@@ -0,0 +1,706 @@
1
+ /**
2
+ * Background poller for active Galaxy workflow invocations.
3
+ *
4
+ * Part 2 of #67. Part 1 added the YAML counters + the Activity-tab UI
5
+ * section that draws progress bars from them. This file is the timer
6
+ * that keeps those counters fresh between agent turns: every
7
+ * POLL_INTERVAL_MS, scan the notebook for in-flight blocks; if any
8
+ * exist, run `checkInvocations` to advance status and write updated
9
+ * counters back to notebook.md.
10
+ *
11
+ * Lifecycle:
12
+ * - session_start → startGalaxyPoller(): unconditionally start the
13
+ * timer. Each tick is cheap when no blocks are in-flight (one
14
+ * notebook read + scan, no Galaxy call).
15
+ * - session_shutdown → stopGalaxyPoller(): clear timer.
16
+ * - Multiple session_start (brain restart) → start() stops any prior
17
+ * timer first; idempotent.
18
+ *
19
+ * Why "always running" instead of stopping on idle:
20
+ * If we stopped at "no in-flight blocks", the next time the agent
21
+ * recorded a new invocation mid-session we'd never wake up — only
22
+ * another session_start would. Avoids a circular import between
23
+ * tools.ts (which records invocations) and this file. The cost is
24
+ * one notebook read + scan per 15s, which is negligible.
25
+ *
26
+ * Concurrency: ticks are guarded by `inFlight` so a slow Galaxy GET
27
+ * doesn't stack ticks. The check itself uses the existing per-notebook
28
+ * lock in withNotebookLock, so a manual `galaxy_invocation_check_all`
29
+ * call from the agent doesn't race the poller.
30
+ */
31
+
32
+ import * as path from "path";
33
+ import { getNotebookPath } from "./state.js";
34
+ import {
35
+ findInvocationBlocks,
36
+ NotebookChangedError,
37
+ readNotebook,
38
+ statNotebook,
39
+ withNotebookLock,
40
+ writeNotebook,
41
+ } from "./notebook-writer.js";
42
+ import { checkInvocations, isInvocationLive } from "./tools.js";
43
+ import {
44
+ getGalaxyConfig,
45
+ galaxyGetInvocation,
46
+ galaxyGetJobDetails,
47
+ sameGalaxyServer,
48
+ } from "./galaxy-api.js";
49
+ import { buildResumePrompt, isResumableOutcome, type GalaxyFollowUp } from "./auto-resume.js";
50
+ import {
51
+ applyJobPollUpdate,
52
+ findJobBlocks,
53
+ isTerminalJobState,
54
+ jobStatusFromGalaxyState,
55
+ type JobYaml,
56
+ } from "./galaxy-job-block.js";
57
+ import { appendActivityEvent } from "./activity.js";
58
+
59
+ // 15s — ~4 polls/min × a few in-flight invocations stays well under
60
+ // usegalaxy.org's per-user rate budget while still feeling live. Background
61
+ // GETs never invoke the model, so this is independent of the model-facing
62
+ // status-read cooldown in galaxy-poll-guard.ts.
63
+ const POLL_INTERVAL_MS = 15_000;
64
+
65
+ let timer: ReturnType<typeof setInterval> | null = null;
66
+ /**
67
+ * The tick currently running, if any. Ticks don't stack -- a slow Galaxy GET
68
+ * would otherwise let the interval pile them up -- and holding the promise
69
+ * rather than a boolean lets a caller wait for the one already in flight.
70
+ */
71
+ let inFlightTick: Promise<void> | null = null;
72
+
73
+ /** Surface a toast to the shell when a background invocation finishes. */
74
+ type PollerNotify = (text: string, level: "info" | "warning" | "error") => void;
75
+ let notify: PollerNotify | null = null;
76
+
77
+ /**
78
+ * Extra work to run on each tick, handed the notebook this tick already read.
79
+ *
80
+ * One hook rather than a second `setInterval`, because everything a second
81
+ * timer would need is already here: the cadence, the notebook read, and the
82
+ * knowledge of what is in flight. A second timer would also be a second thing
83
+ * to remember to stop. The live Galaxy panel registers through this.
84
+ */
85
+ type PollTickHook = (content: string | null) => Promise<void>;
86
+ let tickHook: PollTickHook | null = null;
87
+
88
+ export function setPollTickHook(hook: PollTickHook | null): void {
89
+ tickHook = hook;
90
+ }
91
+
92
+ /** For tests: whether anything is registered, and what. */
93
+ export function getPollTickHook(): PollTickHook | null {
94
+ return tickHook;
95
+ }
96
+
97
+ /**
98
+ * Capture's per-tick work: enrichment of finished runs, and a reconcile every
99
+ * few ticks (galaxy-reconcile.ts). Separate from `tickHook` because it has a
100
+ * different place in the tick -- it runs after this tick's transitions have
101
+ * landed, so a run that just finished is enriched on the same tick -- and
102
+ * because the live panel already owns that slot. Not awaited, for the same
103
+ * reason the panel hook isn't: a slow details fetch must not hold up polling.
104
+ */
105
+ type CaptureTickHook = (tickNumber: number) => Promise<void>;
106
+ let captureHook: CaptureTickHook | null = null;
107
+ let tickCount = 0;
108
+
109
+ export function setCaptureTickHook(hook: CaptureTickHook | null): void {
110
+ captureHook = hook;
111
+ }
112
+
113
+ /**
114
+ * Hand a finished run back to the agent as a queued follow-up, so it verifies
115
+ * outputs itself instead of the toast asking the user to relay. Null when
116
+ * auto-resume is explicitly disabled.
117
+ *
118
+ * Must queue rather than interrupt: delivering a prompt to a brain that is
119
+ * mid-turn fails outright with "Agent is already processing".
120
+ */
121
+ type PollerResume = (text: string) => void;
122
+ let resume: PollerResume | null = null;
123
+
124
+ function notifySafely(text: string, level: "info" | "warning" | "error"): void {
125
+ try {
126
+ notify?.(text, level);
127
+ } catch (err) {
128
+ // A stale shell must not prevent the agent from receiving its follow-up.
129
+ console.error("[galaxy-poller] notification failed:", err);
130
+ }
131
+ }
132
+
133
+ /** Subset of a checkInvocations result entry the poller needs for notifications. */
134
+ interface PollResultEntry {
135
+ invocationId: string;
136
+ notebookAnchor?: string;
137
+ label?: string;
138
+ priorStatus?: string;
139
+ jobSummary?: { ok?: number; running?: number; queued?: number; error?: number; other?: number };
140
+ activeJobs?: number;
141
+ newStatus?: string;
142
+ lastPolledAt?: string;
143
+ autoAction?: string;
144
+ }
145
+
146
+ /**
147
+ * Record a status change in the session's activity log.
148
+ *
149
+ * The poller calls checkInvocations directly rather than through the tool
150
+ * dispatcher, so every transition it made — the ones the user sees as a toast
151
+ * and a rewritten block — used to leave no row behind at all. This is the audit
152
+ * trail for work that advances between turns, with nobody watching.
153
+ */
154
+ function logTransition(payload: Record<string, unknown>): void {
155
+ const nbPath = getNotebookPath();
156
+ if (!nbPath) return;
157
+ appendActivityEvent(path.dirname(nbPath), {
158
+ timestamp: new Date().toISOString(),
159
+ kind: "poll.transition",
160
+ source: "galaxy-poller",
161
+ payload,
162
+ });
163
+ }
164
+
165
+ /**
166
+ * Invocations we've already told the user about a mid-flight job failure for.
167
+ * That one is reported from a block that stays `in_progress` on purpose (the
168
+ * rest of the workflow is still under observation), so unlike a terminal
169
+ * transition it recurs on every tick until the run ends — announce it once.
170
+ * Reset per session in startGalaxyPoller.
171
+ */
172
+ const announcedFailing = new Set<string>();
173
+
174
+ /** A block the poller has seen in flight in the notebook this session. */
175
+ interface TrackedBlock {
176
+ kind: "invocation" | "job";
177
+ id: string;
178
+ label: string;
179
+ /** Consecutive failed liveness checks after the block went missing. */
180
+ checkFailures?: number;
181
+ }
182
+
183
+ /**
184
+ * How many times a missing block's liveness check may fail before we give up on
185
+ * it. A 403 or a 404 doesn't get better by asking again, and retrying forever
186
+ * would spend a Galaxy round trip per tick, per id, for the rest of the
187
+ * session.
188
+ */
189
+ const MAX_MISSING_CHECK_ATTEMPTS = 3;
190
+
191
+ /**
192
+ * Every in-flight block we've seen this session, keyed `<kind>:<id>`. The
193
+ * notebook is the poller's only index of what to watch, so a block that leaves
194
+ * it -- an agent edit, a `bash` rewrite, a hand-pruned file -- takes a live
195
+ * Galaxy run out of Orbit's sight with nothing said. We can't put the block back
196
+ * (it is the user's file, and re-inserting it would fight whoever removed it),
197
+ * but we can refuse to let it go quietly. Reset per session in
198
+ * startGalaxyPoller.
199
+ */
200
+ const trackedActive = new Map<string, TrackedBlock>();
201
+
202
+ function trackKey(kind: TrackedBlock["kind"], id: string): string {
203
+ return `${kind}:${id}`;
204
+ }
205
+
206
+ /**
207
+ * Remember the blocks that are in flight right now, and forget the ones that
208
+ * have reached a terminal status. What survives is exactly the set whose
209
+ * disappearance would cost us a running job.
210
+ */
211
+ function trackActiveBlocks(content: string): void {
212
+ for (const inv of findInvocationBlocks(content)) {
213
+ const key = trackKey("invocation", inv.invocationId);
214
+ if (inv.status === "in_progress") {
215
+ trackedActive.set(key, {
216
+ kind: "invocation",
217
+ id: inv.invocationId,
218
+ label: inv.label || inv.notebookAnchor || inv.invocationId,
219
+ });
220
+ } else {
221
+ trackedActive.delete(key);
222
+ }
223
+ }
224
+ for (const job of findJobBlocks(content)) {
225
+ const key = trackKey("job", job.jobId);
226
+ if (job.status === "in_progress") {
227
+ trackedActive.set(key, {
228
+ kind: "job",
229
+ id: job.jobId,
230
+ label: job.label || job.toolId || job.jobId,
231
+ });
232
+ } else {
233
+ trackedActive.delete(key);
234
+ }
235
+ }
236
+ }
237
+
238
+ /** Ask Galaxy whether a run whose block has vanished is still going. */
239
+ async function isStillLive(block: TrackedBlock): Promise<{ live: boolean; state?: string }> {
240
+ if (block.kind === "invocation") {
241
+ const inv = await galaxyGetInvocation(block.id);
242
+ return { live: isInvocationLive(inv), state: inv.state };
243
+ }
244
+ const details = await galaxyGetJobDetails(block.id);
245
+ return { live: !isTerminalJobState(details.state), state: details.state };
246
+ }
247
+
248
+ /** Say once, in the activity log and in the UI, that a live run left the notebook. */
249
+ function announceMissingBlock(block: TrackedBlock, state: string | undefined): void {
250
+ const nbPath = getNotebookPath();
251
+ if (nbPath) {
252
+ appendActivityEvent(path.dirname(nbPath), {
253
+ timestamp: new Date().toISOString(),
254
+ kind: "poll.block_missing",
255
+ source: "galaxy-poller",
256
+ payload: {
257
+ blockKind: block.kind,
258
+ id: block.id,
259
+ label: block.label,
260
+ galaxyState: state ?? null,
261
+ },
262
+ });
263
+ }
264
+ if (notify) {
265
+ notify(
266
+ `⚠️ Galaxy: "${block.label}" is still ${state ?? "running"} on Galaxy, but its ${block.kind} block is gone from the notebook — Orbit has stopped tracking it.`,
267
+ "warning",
268
+ );
269
+ }
270
+ }
271
+
272
+ /**
273
+ * Compare what we're tracking against what the notebook still holds, and report
274
+ * anything that went missing while Galaxy says the run is alive. A block that
275
+ * disappeared after its run finished is unremarkable: it costs one GET and
276
+ * nothing else.
277
+ */
278
+ async function reportMissingBlocks(content: string): Promise<void> {
279
+ if (trackedActive.size === 0) return;
280
+ const present = new Set<string>();
281
+ for (const inv of findInvocationBlocks(content)) {
282
+ present.add(trackKey("invocation", inv.invocationId));
283
+ }
284
+ for (const job of findJobBlocks(content)) present.add(trackKey("job", job.jobId));
285
+
286
+ const missing = [...trackedActive.entries()].filter(([key]) => !present.has(key));
287
+ if (missing.length === 0) return;
288
+ // No credentials, no verdict: keep the ids and ask again next tick.
289
+ if (!getGalaxyConfig()) return;
290
+
291
+ for (const [key, block] of missing) {
292
+ let result: { live: boolean; state?: string };
293
+ try {
294
+ result = await isStillLive(block);
295
+ } catch (err) {
296
+ // Galaxy briefly unreachable. Stay tracked and ask again next tick; one
297
+ // unreachable id must not cost the others their check. A few attempts in,
298
+ // stop asking -- the answer isn't coming.
299
+ console.error(`[galaxy-poller] ${block.kind} ${block.id} liveness check failed:`, err);
300
+ const failures = (block.checkFailures ?? 0) + 1;
301
+ if (failures >= MAX_MISSING_CHECK_ATTEMPTS) trackedActive.delete(key);
302
+ else trackedActive.set(key, { ...block, checkFailures: failures });
303
+ continue;
304
+ }
305
+ // One verdict per id, either way: the block is gone, so there is nothing
306
+ // left to re-examine. Recording it again re-arms the tracking.
307
+ trackedActive.delete(key);
308
+ if (result.live) announceMissingBlock(block, result.state);
309
+ }
310
+ }
311
+
312
+ /** How many times a job update re-reads and retries before giving up the tick. */
313
+ const MAX_JOB_PERSIST_ATTEMPTS = 3;
314
+
315
+ /**
316
+ * Persist one job's poll result, returning whether it actually landed.
317
+ *
318
+ * Same discipline as persistInvocationUpdates: stamp *before* the read (a stamp
319
+ * taken after would let a write that landed in between look unchanged), apply
320
+ * only poll-owned fields so a concurrent label edit survives, and hand the stamp
321
+ * to writeNotebook so an out-of-band edit fails the compare-and-swap instead of
322
+ * being silently overwritten (#391). The lock alone can't do this -- it only
323
+ * orders Orbit's own writers, and the agent edits notebook.md directly.
324
+ */
325
+ async function persistJobUpdate(
326
+ nbPath: string,
327
+ update: Parameters<typeof applyJobPollUpdate>[1],
328
+ ): Promise<{ written: boolean; priorStatus?: JobYaml["status"] }> {
329
+ let lastError: unknown;
330
+ for (let attempt = 0; attempt < MAX_JOB_PERSIST_ATTEMPTS; attempt++) {
331
+ const stamp = await statNotebook(nbPath);
332
+ // Read regardless of the stat so a genuinely missing notebook surfaces its
333
+ // own ENOENT rather than being dressed up as a lost race.
334
+ const fresh = await readNotebook(nbPath);
335
+ if (!stamp) {
336
+ lastError = new NotebookChangedError(nbPath);
337
+ continue;
338
+ }
339
+ // The status as it is now, not as the tick's opening snapshot had it: the
340
+ // write below refreshes last_polled_at either way, so "we wrote" is not the
341
+ // same question as "we changed the outcome".
342
+ const priorStatus = findJobBlocks(fresh).find((j) => j.jobId === update.jobId)?.status;
343
+ const updated = applyJobPollUpdate(fresh, update);
344
+ // Block gone, or already carrying this result: nothing to write, nothing
345
+ // to announce.
346
+ if (updated === fresh) return { written: false };
347
+ try {
348
+ await writeNotebook(nbPath, updated, stamp);
349
+ return { written: true, priorStatus };
350
+ } catch (error) {
351
+ if (!(error instanceof NotebookChangedError)) throw error;
352
+ lastError = error;
353
+ }
354
+ }
355
+ throw lastError;
356
+ }
357
+
358
+ /** The toast for a job that stopped running, matched to why it stopped. */
359
+ function jobFinishedToast(
360
+ status: ReturnType<typeof jobStatusFromGalaxyState>,
361
+ label: string,
362
+ state: string | undefined,
363
+ willResume = false,
364
+ ): [string, "info" | "warning" | "error"] {
365
+ switch (status) {
366
+ case "completed":
367
+ return [
368
+ `✅ Galaxy: "${label}" finished${willResume ? " — outputs require verification." : " — automatic follow-up disabled."}`,
369
+ "info",
370
+ ];
371
+ case "cancelled":
372
+ return [`⏹️ Galaxy: "${label}" was cancelled (${state}) — it produced no outputs.`, "info"];
373
+ case "skipped":
374
+ return [`⏭️ Galaxy: "${label}" was skipped — its step's condition wasn't met.`, "info"];
375
+ default:
376
+ return [
377
+ `❌ Galaxy: "${label}" failed (${state})${willResume ? " — failure recorded." : " — automatic follow-up disabled."}`,
378
+ "warning",
379
+ ];
380
+ }
381
+ }
382
+
383
+ /** The notebook as it is right now, or null if there isn't one to read. */
384
+ async function readNotebookOrNull(): Promise<string | null> {
385
+ const nbPath = getNotebookPath();
386
+ if (!nbPath) return null;
387
+ try {
388
+ return await readNotebook(nbPath);
389
+ } catch {
390
+ // Notebook missing or unreadable — nothing to advance this tick.
391
+ return null;
392
+ }
393
+ }
394
+
395
+ function hasInProgressInvocations(content: string): boolean {
396
+ return findInvocationBlocks(content).some((b) => b.status === "in_progress");
397
+ }
398
+
399
+ /**
400
+ * Advance in-flight `loom-job` blocks -- single Galaxy tool runs, which have no
401
+ * invocation to poll. One GET per in-flight job, and only for jobs that are
402
+ * still running, so an idle notebook costs nothing beyond the scan the
403
+ * invocation path already does.
404
+ */
405
+ async function tickJobs(content: string, followUps: GalaxyFollowUp[]): Promise<void> {
406
+ const nbPath = getNotebookPath();
407
+ if (!nbPath) return;
408
+
409
+ const pending = findJobBlocks(content).filter((j) => j.status === "in_progress");
410
+ if (pending.length === 0) return;
411
+ const currentServer = getGalaxyConfig()?.url;
412
+ if (!currentServer) return;
413
+
414
+ for (const job of pending) {
415
+ let state: string | undefined;
416
+ try {
417
+ state = (await galaxyGetJobDetails(job.jobId)).state;
418
+ } catch (err) {
419
+ // One unreachable job must not stop the others, or kill the timer.
420
+ console.error(`[galaxy-poller] job ${job.jobId} poll failed:`, err);
421
+ continue;
422
+ }
423
+ if (!isTerminalJobState(state)) {
424
+ // Still running, so there's no transition to record -- but the GET just
425
+ // answered, which is the proof a block the record tool could only write
426
+ // `server_verified: false` is waiting for. Without this the flag would
427
+ // sit false for the whole run and only clear when the job ends.
428
+ if (job.serverVerified === false && sameGalaxyServer(job.galaxyServerUrl, currentServer)) {
429
+ try {
430
+ await withNotebookLock(nbPath, () =>
431
+ // Only the flag and the timestamp: this write knows nothing about
432
+ // the outcome, and the snapshot's status is already older than
433
+ // whatever the fresh read inside persistJobUpdate will see.
434
+ persistJobUpdate(nbPath, {
435
+ jobId: job.jobId,
436
+ lastPolledAt: new Date().toISOString(),
437
+ serverVerified: true,
438
+ }),
439
+ );
440
+ } catch (err) {
441
+ // Nothing was announced, so a lost write costs only a retry next tick.
442
+ console.error(`[galaxy-poller] job ${job.jobId} verification update failed:`, err);
443
+ }
444
+ }
445
+ continue;
446
+ }
447
+
448
+ const status = jobStatusFromGalaxyState(state);
449
+ const polledAt = new Date().toISOString();
450
+ let persisted: { written: boolean; priorStatus?: JobYaml["status"] };
451
+ try {
452
+ persisted = await withNotebookLock(nbPath, () =>
453
+ persistJobUpdate(nbPath, {
454
+ jobId: job.jobId,
455
+ status,
456
+ galaxyState: state,
457
+ lastPolledAt: polledAt,
458
+ // Only the server the block names can confirm the block's id.
459
+ serverVerified: sameGalaxyServer(job.galaxyServerUrl, currentServer),
460
+ }),
461
+ );
462
+ } catch (err) {
463
+ // Lost the write. Say nothing and let the next tick re-poll: the block is
464
+ // still in_progress on disk, so announcing a transition we failed to
465
+ // record would leave the notebook and the user telling different stories.
466
+ console.error(`[galaxy-poller] job ${job.jobId} update failed:`, err);
467
+ continue;
468
+ }
469
+ // The block was deleted mid-poll, or another writer already advanced it.
470
+ // Either way this tick didn't transition anything, so there's no news.
471
+ if (!persisted.written) continue;
472
+ if (persisted.priorStatus === status) continue;
473
+
474
+ const label = job.label || job.toolId || job.jobId;
475
+ logTransition({
476
+ blockKind: "job",
477
+ id: job.jobId,
478
+ label,
479
+ toolId: job.toolId ?? null,
480
+ from: persisted.priorStatus ?? job.status,
481
+ to: status,
482
+ galaxyState: state ?? null,
483
+ lastPolledAt: polledAt,
484
+ });
485
+ const willResume = resume !== null && isResumableOutcome(status);
486
+ notifySafely(...jobFinishedToast(status, label, state, willResume));
487
+ if (isResumableOutcome(status)) {
488
+ followUps.push({
489
+ kind: "job",
490
+ id: job.jobId,
491
+ label,
492
+ notebookAnchor: job.notebookAnchor,
493
+ outcome: status,
494
+ detail: state,
495
+ });
496
+ }
497
+ }
498
+ }
499
+
500
+ /** Run a poll tick now, or hand back the one already running. */
501
+ function tick(): Promise<void> {
502
+ if (inFlightTick) return inFlightTick;
503
+ inFlightTick = runTick().finally(() => {
504
+ inFlightTick = null;
505
+ });
506
+ return inFlightTick;
507
+ }
508
+
509
+ /**
510
+ * Poll once and wait for it. Exported so a caller that wants fresh counters
511
+ * right now doesn't have to sit out the interval.
512
+ */
513
+ export function pollGalaxyNow(): Promise<void> {
514
+ return tick();
515
+ }
516
+
517
+ async function runTick(): Promise<void> {
518
+ const tickNotebook = getNotebookPath();
519
+ const followUps: GalaxyFollowUp[] = [];
520
+ try {
521
+ // One read per tick, shared by everything below: what the notebook says is
522
+ // in flight is the whole of the poller's worklist.
523
+ const content = await readNotebookOrNull();
524
+ // Before the early returns below: a hook that only ran when the notebook
525
+ // had in-flight blocks would be a hook that stops the moment the analysis
526
+ // goes quiet, which is exactly when a panel still has to say something.
527
+ //
528
+ // Deliberately not awaited. A hook is an extra, and this tick's real work
529
+ // -- advancing in-flight invocations and jobs -- must not wait behind one
530
+ // that is talking to a Galaxy that has stopped answering. The hook is
531
+ // responsible for its own re-entrancy; both failure paths are swallowed
532
+ // here so a rejection cannot surface as an unhandled one.
533
+ if (tickHook) {
534
+ try {
535
+ void tickHook(content).catch((err) => {
536
+ console.error("[galaxy-poller] tick hook failed:", err);
537
+ });
538
+ } catch (err) {
539
+ console.error("[galaxy-poller] tick hook threw:", err);
540
+ }
541
+ }
542
+ if (content === null) {
543
+ // The notebook itself is gone, so every block we were watching went with
544
+ // it -- same silencing, one level up. An unreadable-but-present notebook
545
+ // is a transient we say nothing about; an absent one is not.
546
+ const nbPath = getNotebookPath();
547
+ if (nbPath && !(await statNotebook(nbPath))) await reportMissingBlocks("");
548
+ return;
549
+ }
550
+ trackActiveBlocks(content);
551
+ await reportMissingBlocks(content);
552
+
553
+ // Tool runs are tracked separately from workflow invocations and are the
554
+ // only thing advancing in a session that never invoked a workflow (#413).
555
+ await tickJobs(content, followUps);
556
+
557
+ // Cheap path when nothing's in-flight: scan and return.
558
+ if (!hasInProgressInvocations(content)) return;
559
+ if (!getGalaxyConfig()) {
560
+ // Credentials disappeared (user disconnected mid-session). Skip
561
+ // this tick; if creds come back the next tick picks up.
562
+ return;
563
+ }
564
+ const result = await checkInvocations(undefined);
565
+ // Fire a completion toast for any invocation that JUST reached a terminal
566
+ // state this tick. The poller only checks blocks that were in_progress, so
567
+ // an autoAction of completed/failed is a fresh transition that won't recur
568
+ // (the block is terminal next tick and no longer checked) — notify once.
569
+ const results = (result.details as { results?: PollResultEntry[] } | undefined)?.results;
570
+ // Not gated on `notify`: a headless shell has no toast to show but must
571
+ // still hand the finished run back to the agent when auto-resume is on.
572
+ if (Array.isArray(results)) {
573
+ const willResume = resume !== null;
574
+ for (const r of results) {
575
+ const label = r.label || r.notebookAnchor || r.invocationId;
576
+ // A row for what the block's status actually became, and only when it
577
+ // became something else: `autoAction` survives the check's own blanking
578
+ // only for a transition that landed on disk, and a mid-flight failure
579
+ // deliberately leaves the status where it was.
580
+ if (r.autoAction && r.newStatus && r.newStatus !== r.priorStatus) {
581
+ logTransition({
582
+ blockKind: "invocation",
583
+ id: r.invocationId,
584
+ label,
585
+ notebookAnchor: r.notebookAnchor ?? null,
586
+ from: r.priorStatus ?? "in_progress",
587
+ to: r.newStatus,
588
+ outcome: r.autoAction,
589
+ counters: { ...(r.jobSummary ?? {}), active: r.activeJobs ?? 0 },
590
+ lastPolledAt: r.lastPolledAt ?? null,
591
+ });
592
+ }
593
+ if (r.autoAction === "completed") {
594
+ notifySafely(
595
+ `✅ Galaxy: "${label}" finished (${r.jobSummary?.ok ?? 0} jobs ok)${willResume ? " — outputs require verification." : " — automatic follow-up disabled."}`,
596
+ "info",
597
+ );
598
+ followUps.push({
599
+ kind: "invocation",
600
+ id: r.invocationId,
601
+ label,
602
+ notebookAnchor: r.notebookAnchor,
603
+ outcome: "completed",
604
+ });
605
+ } else if (r.autoAction === "failed") {
606
+ notifySafely(
607
+ `❌ Galaxy: "${label}" failed (${r.jobSummary?.error ?? 0} job error(s))${willResume ? " — failure recorded." : " — automatic follow-up disabled."}`,
608
+ "warning",
609
+ );
610
+ followUps.push({
611
+ kind: "invocation",
612
+ id: r.invocationId,
613
+ label,
614
+ notebookAnchor: r.notebookAnchor,
615
+ outcome: "failed",
616
+ detail: `${r.jobSummary?.error ?? 0} job error(s)`,
617
+ });
618
+ } else if (r.autoAction === "cancelled") {
619
+ notifySafely(
620
+ `⏹️ Galaxy: "${label}" was cancelled — ${r.jobSummary?.ok ?? 0} job(s) finished before it stopped.`,
621
+ "info",
622
+ );
623
+ } else if (r.autoAction === "failing" && !announcedFailing.has(r.invocationId)) {
624
+ announcedFailing.add(r.invocationId);
625
+ notifySafely(
626
+ `⚠️ Galaxy: "${label}" — ${r.jobSummary?.error ?? 0} job(s) failed, ${r.activeJobs ?? 0} still running${willResume ? " — failure recorded." : " — automatic follow-up disabled."}`,
627
+ "warning",
628
+ );
629
+ followUps.push({
630
+ kind: "invocation",
631
+ id: r.invocationId,
632
+ label,
633
+ notebookAnchor: r.notebookAnchor,
634
+ outcome: "failing",
635
+ detail: `${r.jobSummary?.error ?? 0} job(s) failed, ${r.activeJobs ?? 0} still running`,
636
+ });
637
+ }
638
+ }
639
+ }
640
+ } catch (err) {
641
+ // Don't kill the timer on a single bad poll — Galaxy may be
642
+ // briefly unreachable. Log and try again on the next tick.
643
+ console.error("[galaxy-poller] tick failed:", err);
644
+ } finally {
645
+ // Batch jobs and workflows into one turn, even if a later poll request
646
+ // failed. Queuing each finished import separately floods the agent.
647
+ // Deliver through whoever owns the poller now, not whoever started this
648
+ // tick: the transitions are already persisted, so a replacement session
649
+ // on the same notebook would never see them in_progress again. A stopped
650
+ // poller has no resume, and a different notebook's session isn't ours.
651
+ const deliver = resume;
652
+ if (deliver && followUps.length > 0 && getNotebookPath() === tickNotebook) {
653
+ try {
654
+ deliver(buildResumePrompt(followUps));
655
+ } catch (err) {
656
+ console.error("[galaxy-poller] auto-resume send failed:", err);
657
+ }
658
+ }
659
+ tickCount++;
660
+ if (captureHook) {
661
+ try {
662
+ void captureHook(tickCount).catch((err) => {
663
+ console.error("[galaxy-poller] capture hook failed:", err);
664
+ });
665
+ } catch (err) {
666
+ console.error("[galaxy-poller] capture hook threw:", err);
667
+ }
668
+ }
669
+ }
670
+ }
671
+
672
+ export function startGalaxyPoller(notifyFn?: PollerNotify, resumeFn?: PollerResume): void {
673
+ stopGalaxyPoller();
674
+ // Capture the shell notifier (from the session_start ctx) so a completed
675
+ // background invocation can toast the user. Refreshed each session_start.
676
+ notify = notifyFn ?? null;
677
+ // Null when auto-resume is disabled; the caller decides, so the poller
678
+ // stays free of config lookups on a 15s timer.
679
+ resume = resumeFn ?? null;
680
+ announcedFailing.clear();
681
+ trackedActive.clear();
682
+ // Idempotent: a brain restart triggers a new session_start without
683
+ // session_shutdown firing first in some failure modes. Stop any
684
+ // pre-existing timer so we don't double-poll.
685
+ // Fire one immediate tick so a session resumed with in-flight blocks
686
+ // gets fresh counters within the first second instead of waiting 15s.
687
+ void tick();
688
+ const interval = setInterval(tick, POLL_INTERVAL_MS);
689
+ // A background refresher must never be the reason the process stays alive.
690
+ // In print/rpc modes (`--mode json`, evals) the work finishes and nothing
691
+ // else holds the loop, so an armed interval kept the process up until
692
+ // something killed it; session_shutdown clears the timer, but relying on
693
+ // shutdown running is what made that a 15s-per-run tax when it didn't.
694
+ // Interactive and Orbit sessions are held open by stdin, so unref costs
695
+ // them nothing.
696
+ interval.unref?.();
697
+ timer = interval;
698
+ }
699
+
700
+ export function stopGalaxyPoller(): void {
701
+ resume = null;
702
+ if (timer) {
703
+ clearInterval(timer);
704
+ timer = null;
705
+ }
706
+ }