@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,707 @@
1
+ /**
2
+ * Auto-registration: every Galaxy submission gets a notebook block, the
3
+ * moment it happens, without the agent being asked to do anything.
4
+ *
5
+ * Recording used to be model-initiated -- prose in the system prompt asking
6
+ * for `galaxy_invocation_record` after a submission, and a record tool that
7
+ * verified nothing about the id it was handed. A turn that died between the
8
+ * submit and the record left a running job nobody was tracking, and a
9
+ * distracted model left the same. This hook closes that by reading the id out
10
+ * of Galaxy's own response to the submission, which is also what makes
11
+ * `server_verified: true` mean anything.
12
+ *
13
+ * Two placement facts. It is registered in the mode-independent part of
14
+ * index.ts rather than inside the exec-guard, because the guard is skipped
15
+ * when `LOOM_LOCAL_EXEC=off` (the web/container shell) and capture has to
16
+ * work there too. And it hangs off `tool_execution_start` as well as
17
+ * `tool_execution_end`, because pi's end event carries only `{toolCallId,
18
+ * toolName, result, isError}` -- the tool's *arguments* are on the start
19
+ * event, and `run_user_tool`'s uuid and the uploads' file names exist nowhere
20
+ * else.
21
+ *
22
+ * Attribution is captured at dispatch, not at result. The attempt id is
23
+ * minted when the tool starts and the step anchor is read then too, so a
24
+ * submission that takes thirty seconds to answer is attributed to the step
25
+ * that made it rather than to whatever the agent moved on to. That is the
26
+ * whole reason for the in-flight map.
27
+ */
28
+
29
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
30
+ import * as path from "path";
31
+ import { stringify as stringifyYaml } from "yaml";
32
+ import { appendActivityEvent } from "./activity";
33
+ import { getGalaxyConfig } from "./galaxy-api";
34
+ import {
35
+ isTerminalJobState,
36
+ jobStatusFromGalaxyState,
37
+ locateJobBlock,
38
+ upsertJobBlock,
39
+ type JobYaml,
40
+ } from "./galaxy-job-block";
41
+ import { hasUdtBlock, upsertUdtBlock } from "./galaxy-udt-block";
42
+ import {
43
+ isSubmissionTool,
44
+ parseGalaxyResultEnvelope,
45
+ parseSubmission,
46
+ resolveResultPayload,
47
+ type ParsedSubmission,
48
+ type ResolvedResult,
49
+ } from "./galaxy-submission";
50
+ import type { HarnessBlockFields } from "./harness-block-fields";
51
+ import {
52
+ NotebookChangedError,
53
+ locateInvocationBlock,
54
+ readNotebook,
55
+ statNotebook,
56
+ upsertInvocationBlock,
57
+ withNotebookLock,
58
+ writeNotebook,
59
+ type InvocationYaml,
60
+ } from "./notebook-writer";
61
+ import { readMcpOutputFile } from "./mcp-output";
62
+ import { galaxyOutputStore } from "./galaxy-output-store";
63
+ import {
64
+ ensureAttemptRecord,
65
+ provenanceRelativePath,
66
+ writeProvenanceSidecar,
67
+ } from "./galaxy-provenance";
68
+ import { getCurrentStepAnchor, getNotebookPath, setCurrentStepAnchor } from "./state";
69
+ import { ulid } from "./ulid";
70
+ import type { GalaxyToolFamily } from "../../shared/galaxy-tool-family.js";
71
+
72
+ /** What a block carries when nothing pointed the submission at a plan step. */
73
+ export const UNATTRIBUTED = "unattributed";
74
+
75
+ /** Where per-attempt provenance lives, relative to the analysis directory. */
76
+ export const PROVENANCE_DIR = path.join(".loom", "provenance");
77
+ export const UDT_PROVENANCE_DIR = path.join(PROVENANCE_DIR, "udt");
78
+
79
+ /**
80
+ * What the winning write attempt did. The activity row is built from this
81
+ * rather than from the parsed submission, so a replay that declined to
82
+ * overwrite an id cannot be announced as having recorded it.
83
+ */
84
+ interface WriteOutcome {
85
+ udtDefinition?: string;
86
+ udtPending: boolean;
87
+ /** Ids a replay left alone because a block already carried them. */
88
+ replayCollisions: string[];
89
+ wroteInvocation?: string;
90
+ wroteJobs: string[];
91
+ wroteUdt?: string;
92
+ }
93
+
94
+ interface Dispatch {
95
+ attemptId: string;
96
+ toolName: string;
97
+ args: Record<string, unknown>;
98
+ stepAnchor: string;
99
+ submittedAt: string;
100
+ replayed: boolean;
101
+ }
102
+
103
+ /**
104
+ * In-flight submissions, keyed by pi's tool call id.
105
+ *
106
+ * Bounded because a start without a matching end is possible -- an aborted
107
+ * turn, a tool that never returns -- and an unbounded map in a long session
108
+ * is a slow leak. The cap is far above any real concurrent tool count. When
109
+ * it is hit the oldest entry goes, and that submission loses its whole
110
+ * dispatch record: its result is still registered, but with a fresh attempt
111
+ * id, no arguments, and `unattributed`. It never gets someone else's.
112
+ */
113
+ const MAX_IN_FLIGHT = 256;
114
+ const inFlight = new Map<string, Dispatch>();
115
+
116
+ /** Test seam: drop in-flight state between cases. */
117
+ export function resetSubmissionCapture(): void {
118
+ inFlight.clear();
119
+ }
120
+
121
+ function rememberDispatch(toolCallId: string, toolName: string, args: unknown): Dispatch {
122
+ const dispatch: Dispatch = {
123
+ attemptId: ulid(),
124
+ toolName,
125
+ args: (args && typeof args === "object" ? args : {}) as Record<string, unknown>,
126
+ stepAnchor: getCurrentStepAnchor() ?? UNATTRIBUTED,
127
+ submittedAt: new Date().toISOString(),
128
+ // A real tool call, watched from start to end.
129
+ replayed: false,
130
+ };
131
+ if (inFlight.size >= MAX_IN_FLIGHT) {
132
+ const oldest = inFlight.keys().next();
133
+ if (!oldest.done) inFlight.delete(oldest.value);
134
+ }
135
+ inFlight.set(toolCallId, dispatch);
136
+ return dispatch;
137
+ }
138
+
139
+ /** Supplied by a caller that knows the dispatch details but had no start event. */
140
+ export interface DispatchOverride {
141
+ args?: Record<string, unknown>;
142
+ stepAnchor?: string | null;
143
+ /**
144
+ * This submission was read out of a fixture, not out of Galaxy. The blocks
145
+ * it produces make no provenance claim: see `harnessFields`.
146
+ */
147
+ replayed?: boolean;
148
+ }
149
+
150
+ /**
151
+ * Recover the dispatch record, or synthesise one.
152
+ *
153
+ * With no in-flight record and no override we never saw the dispatch, so we do
154
+ * NOT fall back to the current step anchor: that is exactly the misattribution
155
+ * the capture-at-dispatch design exists to avoid. Unattributed is the honest
156
+ * answer. An override is itself a dispatch record -- the replay seam passes
157
+ * one because it has no start event to pair with -- so it may name the step.
158
+ */
159
+ function takeDispatch(toolCallId: string, toolName: string, override?: DispatchOverride): Dispatch {
160
+ const found = inFlight.get(toolCallId);
161
+ if (found) {
162
+ inFlight.delete(toolCallId);
163
+ return found;
164
+ }
165
+ return {
166
+ attemptId: ulid(),
167
+ toolName,
168
+ args: override?.args ?? {},
169
+ stepAnchor: override
170
+ ? (override.stepAnchor ?? getCurrentStepAnchor() ?? UNATTRIBUTED)
171
+ : UNATTRIBUTED,
172
+ submittedAt: new Date().toISOString(),
173
+ replayed: override?.replayed === true,
174
+ };
175
+ }
176
+
177
+ function sessionDir(): string | null {
178
+ const nb = getNotebookPath();
179
+ return nb ? path.dirname(nb) : null;
180
+ }
181
+
182
+ function record(kind: string, payload: Record<string, unknown>): void {
183
+ const dir = sessionDir();
184
+ if (!dir) return;
185
+ appendActivityEvent(dir, {
186
+ timestamp: new Date().toISOString(),
187
+ kind,
188
+ source: "submission-capture",
189
+ payload,
190
+ });
191
+ }
192
+
193
+ // ─────────────────────────────────────────────────────────────────────────────
194
+ // Filenames
195
+ // ─────────────────────────────────────────────────────────────────────────────
196
+
197
+ /**
198
+ * Make a Galaxy-supplied tool id safe to use as a filename.
199
+ *
200
+ * The id reaches us from Galaxy, but Galaxy derived it from the agent's own
201
+ * tool definition, so it is agent-influenced and a path separator or a `..`
202
+ * in it would write outside `.loom/provenance/udt/`. Everything outside a
203
+ * conservative allowlist becomes an underscore, leading dots go, and the
204
+ * result is capped; an id that sanitises away to nothing is rejected by the
205
+ * caller rather than written to some default name.
206
+ */
207
+ export function safeProvenanceFilename(toolId: string): string | null {
208
+ const cleaned = toolId
209
+ .replace(/[^A-Za-z0-9._-]/g, "_")
210
+ .replace(/^\.+/, "")
211
+ .slice(0, 120);
212
+ if (!cleaned || /^_+$/.test(cleaned)) return null;
213
+ return cleaned;
214
+ }
215
+
216
+ // ─────────────────────────────────────────────────────────────────────────────
217
+ // Writing the record
218
+ // ─────────────────────────────────────────────────────────────────────────────
219
+
220
+ /**
221
+ * The provenance the upsert functions will not take from a caller's block
222
+ * object. `server_verified` is deliberately not one of them: it is the record
223
+ * tools' own tri-state field, so the hook sets it on the block like they do --
224
+ * with `true`, which it has earned, having read the id out of Galaxy's answer
225
+ * to this very submission.
226
+ *
227
+ * A replayed submission claims neither. `submitted_by: harness` means Orbit
228
+ * watched the submission happen and `server_verified: true` means it read the
229
+ * id out of the server's own answer, and under `LOOM_SUBMISSION_REPLAY` both
230
+ * came out of a file on disk -- no tool ran and no server was asked. The
231
+ * `submission.replay` activity row says so, but that row lives in a sidecar
232
+ * the analysis repo gitignores, and the notebook is the durable record: a
233
+ * block written from a fixture must not read like one written from a run. The
234
+ * rest still rides along, because `attempt_id` and `enrichment` are facts
235
+ * about the record rather than claims about a server.
236
+ */
237
+ function harnessFields(dispatch: Dispatch, historyId?: string): HarnessBlockFields {
238
+ return {
239
+ attemptId: dispatch.attemptId,
240
+ ...(historyId ? { historyId } : {}),
241
+ ...(dispatch.replayed ? {} : { submittedBy: "harness" as const }),
242
+ enrichment: "pending",
243
+ enrichmentAttempts: 0,
244
+ };
245
+ }
246
+
247
+ /**
248
+ * Write every block this submission produces in one locked read-modify-write.
249
+ *
250
+ * One lock for the whole set, not one per job: a mapped-over run produces a
251
+ * block per job, and N separate read-modify-write cycles against the same
252
+ * file is N chances to lose one to a concurrent writer.
253
+ */
254
+ async function writeBlocks(
255
+ notebookPath: string,
256
+ submission: ParsedSubmission,
257
+ dispatch: Dispatch,
258
+ ): Promise<WriteOutcome> {
259
+ const udtPending = submission.kind === "udt" && !!submission.udt;
260
+ const galaxyServerUrl = getGalaxyConfig()?.url ?? "";
261
+ const harness = harnessFields(dispatch, submission.historyId);
262
+ let udtDefinition: string | undefined;
263
+ // What the last (and therefore the winning) `applyBlocks` attempt actually
264
+ // did. Rebuilt on every attempt, because the CAS may run it more than once
265
+ // against fresh content, and only the attempt that lands is true.
266
+ let replayCollisions: string[] = [];
267
+ let wroteInvocation: string | undefined;
268
+ let wroteJobs: string[] = [];
269
+ let wroteUdt: string | undefined;
270
+
271
+ /**
272
+ * A replay must not write over a block that is already there.
273
+ *
274
+ * Replay rebuilds a notebook from fixtures, and a block already carrying
275
+ * that id was written by something that actually happened -- overwriting it
276
+ * would put a fixture's label, anchor and timestamp on a real run, and the
277
+ * carry-forward would hand the replay the real block's `submitted_by:
278
+ * harness` on the way through, which is exactly the claim a replayed block
279
+ * is not allowed to make. Skipping is the only answer that leaves both
280
+ * records honest.
281
+ */
282
+ const replayWouldOverwrite = (
283
+ content: string,
284
+ id: string,
285
+ kind: "invocation" | "job" | "udt",
286
+ ): boolean => {
287
+ if (!dispatch.replayed) return false;
288
+ const present =
289
+ kind === "invocation"
290
+ ? locateInvocationBlock(content, id).present
291
+ : kind === "job"
292
+ ? locateJobBlock(content, id).present
293
+ : hasUdtBlock(content, id);
294
+ if (present) replayCollisions.push(id);
295
+ return present;
296
+ };
297
+
298
+ /** Apply this submission's blocks to whatever the notebook currently says. */
299
+ const applyBlocks = (content: string): string => {
300
+ let next = content;
301
+ replayCollisions = [];
302
+ wroteInvocation = undefined;
303
+ wroteJobs = [];
304
+ wroteUdt = undefined;
305
+
306
+ if (submission.kind === "invocation" && submission.invocationId) {
307
+ const inv: InvocationYaml = {
308
+ invocationId: submission.invocationId,
309
+ galaxyServerUrl,
310
+ notebookAnchor: dispatch.stepAnchor,
311
+ label: submission.label,
312
+ submittedAt: dispatch.submittedAt,
313
+ status: "in_progress",
314
+ ...(dispatch.replayed ? {} : { serverVerified: true }),
315
+ };
316
+ if (!replayWouldOverwrite(next, submission.invocationId, "invocation")) {
317
+ next = upsertInvocationBlock(next, inv, harness);
318
+ wroteInvocation = submission.invocationId;
319
+ }
320
+ }
321
+
322
+ for (const job of submission.jobs ?? []) {
323
+ if (replayWouldOverwrite(next, job.jobId, "job")) continue;
324
+ const block: JobYaml = {
325
+ jobId: job.jobId,
326
+ galaxyServerUrl,
327
+ notebookAnchor: dispatch.stepAnchor,
328
+ label: submission.label,
329
+ ...(job.toolId ? { toolId: job.toolId } : {}),
330
+ submittedAt: dispatch.submittedAt,
331
+ // A job that was already terminal when the call returned must not be
332
+ // written as in_progress: the poller would "discover" it finished on
333
+ // its next tick and wake the agent to verify work it already saw.
334
+ ...(isTerminalJobState(job.state)
335
+ ? { status: jobStatusFromGalaxyState(job.state), galaxyState: job.state }
336
+ : { status: "in_progress" as const }),
337
+ ...(dispatch.replayed ? {} : { serverVerified: true }),
338
+ };
339
+ // tool_version is only ever in the submission response -- GET
340
+ // /api/jobs/{id} drops it -- so seed the job summary with it now rather
341
+ // than hoping enrichment can find it later.
342
+ wroteJobs.push(job.jobId);
343
+ next = upsertJobBlock(next, block, {
344
+ ...harness,
345
+ ...(job.historyId && !submission.historyId ? { historyId: job.historyId } : {}),
346
+ jobs: [
347
+ {
348
+ jobId: job.jobId,
349
+ ...(job.toolId ? { toolId: job.toolId } : {}),
350
+ ...(job.toolVersion ? { toolVersion: job.toolVersion } : {}),
351
+ },
352
+ ],
353
+ });
354
+ }
355
+
356
+ if (
357
+ submission.udt &&
358
+ udtDefinition &&
359
+ !replayWouldOverwrite(next, submission.udt.uuid, "udt")
360
+ ) {
361
+ wroteUdt = submission.udt.uuid;
362
+ next = upsertUdtBlock(next, {
363
+ toolId: submission.udt.toolId,
364
+ toolUuid: submission.udt.uuid,
365
+ definition: udtDefinition,
366
+ createdAt: dispatch.submittedAt,
367
+ notebookAnchor: dispatch.stepAnchor,
368
+ attemptId: dispatch.attemptId,
369
+ });
370
+ }
371
+
372
+ return next;
373
+ };
374
+
375
+ // The definition file is written once, outside the retry: it is keyed by
376
+ // uuid and created exclusively, so re-running applyBlocks must not re-write
377
+ // it.
378
+ if (submission.kind === "udt" && submission.udt) {
379
+ udtDefinition =
380
+ (await writeUdtDefinition(
381
+ path.dirname(notebookPath),
382
+ submission.udt.toolId,
383
+ submission.udt.uuid,
384
+ submission.udt.representation,
385
+ )) ?? undefined;
386
+ }
387
+
388
+ await withNotebookLock(notebookPath, async () => {
389
+ // Compare-and-swap, retried, rather than a blind write. The lock only
390
+ // serialises writers inside THIS process; the agent's own edit/write
391
+ // tools, a user's editor, and a second Orbit process on the same notebook
392
+ // are all outside it, and a submission lands at an arbitrary moment
393
+ // relative to them. Without the stamp, capture renames content it read
394
+ // before someone else's edit straight over that edit (#391).
395
+ for (let attempt = 0; ; attempt++) {
396
+ const stamp = await statNotebook(notebookPath);
397
+ const content = await readNotebook(notebookPath);
398
+ try {
399
+ await writeNotebook(notebookPath, applyBlocks(content), stamp ?? undefined);
400
+ return;
401
+ } catch (err) {
402
+ // Rebuild on the current bytes and try again. After a few collisions
403
+ // give up and let the caller record the submission as unrecorded
404
+ // rather than claim a block that never landed.
405
+ if (!(err instanceof NotebookChangedError) || attempt >= 2) throw err;
406
+ }
407
+ }
408
+ });
409
+
410
+ return {
411
+ ...(udtDefinition ? { udtDefinition } : {}),
412
+ udtPending,
413
+ replayCollisions,
414
+ wroteInvocation,
415
+ wroteJobs,
416
+ wroteUdt,
417
+ };
418
+ }
419
+
420
+ /**
421
+ * Persist a user-defined tool's definition beside the notebook. Returns the
422
+ * analysis-relative path written, or null when the id can't be made into a
423
+ * safe filename.
424
+ */
425
+ async function writeUdtDefinition(
426
+ analysisDir: string,
427
+ toolId: string,
428
+ uuid: string,
429
+ representation: unknown,
430
+ ): Promise<string | null> {
431
+ // The uuid is in the filename, not just the tool id, because the uuid is
432
+ // what identifies a definition: recreating `clean_table` yields a new uuid
433
+ // and a new (possibly different) definition, and naming by tool id alone
434
+ // meant the second write overwrote the first while both notebook blocks
435
+ // went on pointing at the surviving file. It also settles the case where
436
+ // two distinct tool ids sanitise to the same name.
437
+ const safeTool = safeProvenanceFilename(toolId);
438
+ const safeUuid = safeProvenanceFilename(uuid);
439
+ if (!safeUuid) return null;
440
+ const stem = safeTool ? `${safeTool}-${safeUuid}` : safeUuid;
441
+
442
+ const relative = path.join(UDT_PROVENANCE_DIR, `${stem}.yaml`);
443
+ // Exclusive create: a planted symlink is refused and an existing definition
444
+ // kept (the uuid is in the name, so the same uuid means the same definition).
445
+ // Anything else is a real failure and the caller reports the submission as
446
+ // unrecorded.
447
+ await writeProvenanceSidecar(analysisDir, ["udt", `${stem}.yaml`], stringifyYaml(representation));
448
+ // Always POSIX separators in the notebook: the block is read on whatever
449
+ // platform opens the analysis next, not the one that wrote it.
450
+ return relative.split(path.sep).join("/");
451
+ }
452
+
453
+ // ─────────────────────────────────────────────────────────────────────────────
454
+ // The hook
455
+ // ─────────────────────────────────────────────────────────────────────────────
456
+
457
+ /**
458
+ * Re-read a result that reached the hook cut short.
459
+ *
460
+ * Past 20 KB pi's MCP support cuts the middle out of the text and saves the
461
+ * full copy to a temp file; the in-process Galaxy tools show a preview instead
462
+ * and keep the full copy in the in-memory output store. Either way what's left
463
+ * is not valid JSON, so without this a big mapped-over submission -- precisely
464
+ * the one whose record matters most -- would log `submission.unparsed`.
465
+ */
466
+ // A big mapped-over submission is exactly the one whose record matters, so read
467
+ // well past mcp_read_output's preview limit before giving up on it.
468
+ const SUBMISSION_MAX_BYTES = 256 * 1024 * 1024;
469
+
470
+ async function rereadTruncated(resolved: ResolvedResult): Promise<ResolvedResult> {
471
+ if (resolved.outputId) {
472
+ const text = galaxyOutputStore().get(resolved.outputId);
473
+ if (text !== undefined) return { ...resolved, value: undefined, text };
474
+ }
475
+ if (!resolved.truncatedPath) return resolved;
476
+ try {
477
+ // Same confinement mcp_read_output applies: only a file pi itself wrote.
478
+ return {
479
+ ...resolved,
480
+ value: undefined,
481
+ text: await readMcpOutputFile(resolved.truncatedPath, SUBMISSION_MAX_BYTES),
482
+ };
483
+ } catch {
484
+ return resolved;
485
+ }
486
+ }
487
+
488
+ /**
489
+ * Handle one finished submission tool. Exported so the Tier-1 scenarios can
490
+ * replay a recorded result through exactly this path.
491
+ *
492
+ * `toolName` is the name the model called; it picks the parser and is what the
493
+ * activity rows record.
494
+ */
495
+ export async function handleSubmissionResult(
496
+ toolCallId: string,
497
+ toolName: string,
498
+ result: unknown,
499
+ isError: boolean,
500
+ dispatchOverride?: DispatchOverride,
501
+ ): Promise<void> {
502
+ const dispatch = takeDispatch(toolCallId, toolName, dispatchOverride);
503
+
504
+ // A failed submission is not a submission: the Galaxy tools mark a
505
+ // success=false envelope as an error, and nothing was created.
506
+ if (isError) return;
507
+
508
+ const notebookPath = getNotebookPath();
509
+ if (!notebookPath) return;
510
+
511
+ let resolved = resolveResultPayload(result);
512
+ let outcome = parseSubmission(toolName, dispatch.args, resolved);
513
+ // Re-read the full-output file ONLY when the inline payload was never a
514
+ // readable envelope -- that is the truncation case this exists for. If the
515
+ // envelope parsed and the tool-specific parse still said no, we understood
516
+ // the answer and it was "nothing to record"; going to the full-output file then
517
+ // would let a different payload overturn a verdict we already reached.
518
+ if (
519
+ !outcome.ok &&
520
+ (resolved.truncatedPath || resolved.outputId) &&
521
+ parseGalaxyResultEnvelope(resolved) === null &&
522
+ toolName !== "galaxy_upload_local_file"
523
+ ) {
524
+ resolved = await rereadTruncated(resolved);
525
+ outcome = parseSubmission(toolName, dispatch.args, resolved);
526
+ }
527
+
528
+ if (!outcome.ok) {
529
+ record("submission.unparsed", {
530
+ tool: toolName,
531
+ attempt_id: dispatch.attemptId,
532
+ step_anchor: dispatch.stepAnchor,
533
+ reason: outcome.reason,
534
+ });
535
+ return;
536
+ }
537
+
538
+ const submission = outcome.submission;
539
+ let written: WriteOutcome;
540
+ try {
541
+ written = await writeBlocks(notebookPath, submission, dispatch);
542
+ } catch (err) {
543
+ // The run is real and running whether or not we managed to write it down;
544
+ // say so rather than claiming a registration that did not land.
545
+ record("submission.unparsed", {
546
+ tool: toolName,
547
+ attempt_id: dispatch.attemptId,
548
+ step_anchor: dispatch.stepAnchor,
549
+ reason: `could not write the record: ${err instanceof Error ? err.message : String(err)}`,
550
+ });
551
+ return;
552
+ }
553
+
554
+ // A user-defined tool whose definition could not be stored is not recorded:
555
+ // the block would point at a file that is not there, and the whole reason
556
+ // the harness intercepts a UDT creation is to keep the definition. Say
557
+ // unparsed instead of claiming a registration.
558
+ if (written.udtPending && !written.udtDefinition) {
559
+ record("submission.unparsed", {
560
+ tool: toolName,
561
+ attempt_id: dispatch.attemptId,
562
+ step_anchor: dispatch.stepAnchor,
563
+ reason: "could not store the tool definition, so the creation is unrecorded",
564
+ });
565
+ return;
566
+ }
567
+
568
+ if (written.replayCollisions.length > 0) {
569
+ record("submission.replay_skipped", {
570
+ tool: toolName,
571
+ attempt_id: dispatch.attemptId,
572
+ step_anchor: dispatch.stepAnchor,
573
+ ids: written.replayCollisions,
574
+ reason: "the notebook already has a block for these ids; a fixture must not overwrite one",
575
+ });
576
+ }
577
+
578
+ // Nothing landed, so there is no registration to announce. Saying otherwise
579
+ // would put a row in the log claiming a block that is not there -- the same
580
+ // untruth `submission.unparsed` exists to avoid on the other side.
581
+ const wroteNothing =
582
+ !written.wroteInvocation && written.wroteJobs.length === 0 && !written.wroteUdt;
583
+ if (wroteNothing) return;
584
+
585
+ // /execute's step anchor names the step it started on, but one /execute now
586
+ // carries on through the authorized plan. Only the first run it lands is
587
+ // known to be for that step; leaving the anchor armed filed step 2 and 3
588
+ // under step 1, which the evidence gate then read as step 1's evidence.
589
+ // Later runs come out unattributed until the model binds them.
590
+ if (!dispatch.replayed && dispatch.stepAnchor === getCurrentStepAnchor()) {
591
+ setCurrentStepAnchor(null);
592
+ }
593
+
594
+ // The provenance record is created now, while the ids this attempt owns are
595
+ // the ones Galaxy just answered with. Enrichment only ever adds to a record
596
+ // whose owned ids include the block asking, and the block's attempt_id is
597
+ // agent-editable text -- so this is the write that pins which runs the
598
+ // attempt is about. A failure here costs enrichment a fallback, not the
599
+ // registration: the block is already written.
600
+ const provenance = await recordAttempt(notebookPath, submission, dispatch, written);
601
+
602
+ record("submission.registered", {
603
+ tool: toolName,
604
+ attempt_id: dispatch.attemptId,
605
+ step_anchor: dispatch.stepAnchor,
606
+ kind: submission.kind,
607
+ label: submission.label,
608
+ submitted_by: dispatch.replayed ? "replay" : "harness",
609
+ ...(submission.historyId ? { history_id: submission.historyId } : {}),
610
+ // The ids that were actually written, not the ids the result carried: a
611
+ // mapped-over replay can land some of its jobs and skip others.
612
+ ...(written.wroteInvocation ? { invocation_id: written.wroteInvocation } : {}),
613
+ ...(written.wroteJobs.length > 0 ? { job_ids: written.wroteJobs } : {}),
614
+ ...(written.wroteUdt && submission.udt
615
+ ? { tool_id: submission.udt.toolId, tool_uuid: written.wroteUdt }
616
+ : {}),
617
+ // The path is reported from what was actually written, not from what we
618
+ // meant to write, so the row can't claim a definition that never landed.
619
+ ...(written.udtDefinition ? { definition: written.udtDefinition } : {}),
620
+ ...(submission.partial ? { partial: true } : {}),
621
+ ...(provenance ? { provenance } : {}),
622
+ });
623
+ }
624
+
625
+ async function recordAttempt(
626
+ notebookPath: string,
627
+ submission: ParsedSubmission,
628
+ dispatch: Dispatch,
629
+ written: WriteOutcome,
630
+ ): Promise<string | null> {
631
+ const kind = written.wroteInvocation
632
+ ? "invocation"
633
+ : written.wroteJobs.length > 0
634
+ ? "jobs"
635
+ : null;
636
+ if (!kind) return null;
637
+ try {
638
+ await ensureAttemptRecord(path.dirname(notebookPath), {
639
+ attemptId: dispatch.attemptId,
640
+ kind,
641
+ galaxyServerUrl: getGalaxyConfig()?.url ?? "",
642
+ historyId: submission.historyId ?? submission.jobs?.find((j) => j.historyId)?.historyId,
643
+ submittedBy: dispatch.replayed ? "replay" : "harness",
644
+ ids:
645
+ kind === "invocation"
646
+ ? { invocation_id: written.wroteInvocation }
647
+ : { job_ids: written.wroteJobs },
648
+ origin: "submission",
649
+ seeds: Object.fromEntries(
650
+ (submission.jobs ?? [])
651
+ .filter((j) => written.wroteJobs.includes(j.jobId))
652
+ .map((j) => [
653
+ j.jobId,
654
+ {
655
+ ...(j.toolId ? { tool_id: j.toolId } : {}),
656
+ ...(j.toolVersion ? { tool_version: j.toolVersion } : {}),
657
+ },
658
+ ]),
659
+ ),
660
+ createdAt: dispatch.submittedAt,
661
+ });
662
+ return provenanceRelativePath(dispatch.attemptId);
663
+ } catch (err) {
664
+ console.error("[submission-capture] provenance record not written:", err);
665
+ return null;
666
+ }
667
+ }
668
+
669
+ /**
670
+ * The tool name when it is a submission this shell offers, else undefined: a
671
+ * Galaxy tool the family names, or Orbit's own galaxy_upload_local_file, which is
672
+ * outside the family. A name the family does not claim is not this shell's tool,
673
+ * so it is not a submission either.
674
+ */
675
+ export function submissionToolName(toolName: string, family: GalaxyToolFamily): string | undefined {
676
+ if (toolName === "galaxy_upload_local_file") return toolName;
677
+ const tool = family.toolName(toolName);
678
+ return tool !== undefined && isSubmissionTool(tool) ? tool : undefined;
679
+ }
680
+
681
+ export function registerSubmissionCapture(pi: ExtensionAPI, family: GalaxyToolFamily): void {
682
+ pi.on("tool_execution_start", async (event) => {
683
+ const toolName = submissionToolName(event.toolName, family);
684
+ if (!toolName) return;
685
+ const args = (event.args && typeof event.args === "object" ? event.args : {}) as Record<
686
+ string,
687
+ unknown
688
+ >;
689
+ rememberDispatch(event.toolCallId, toolName, args);
690
+ });
691
+
692
+ pi.on("tool_execution_end", async (event) => {
693
+ const toolName = submissionToolName(event.toolName, family);
694
+ if (!toolName) return;
695
+ try {
696
+ await handleSubmissionResult(
697
+ event.toolCallId,
698
+ toolName,
699
+ event.result,
700
+ event.isError === true,
701
+ );
702
+ } catch (err) {
703
+ // Never let capture take the turn down: the submission already happened.
704
+ console.error("[submission-capture] failed:", err);
705
+ }
706
+ });
707
+ }