@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,435 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { parse as parseYaml } from "yaml";
5
+ import { findSkillRepo, listEnabledSkillRepos, type ConfiguredSkillRepo } from "./skills";
6
+ import { resolveStateDir } from "../../shared/state-dir.js";
7
+ import {
8
+ SKILLS_SURFACE_ID,
9
+ selectSkills as selectSurfaceSkills,
10
+ } from "../../shared/skills-router.js";
11
+ import {
12
+ STAGING_REPO_NAME,
13
+ hasBundledContent,
14
+ isBundledRepo,
15
+ readBundledCatalog,
16
+ } from "./vendor-skills";
17
+ export type { ConfiguredSkillRepo };
18
+
19
+ /** The product-surface id Orbit claims. A skill opts in with `surfaces: [loom]`. */
20
+ export const SURFACE_ID = SKILLS_SURFACE_ID;
21
+
22
+ /** Catalog freshness window. SKILL.md frontmatter + the tree listing use this; deep refs stay 24h. */
23
+ export const CATALOG_TTL_MS = 60 * 60 * 1000;
24
+
25
+ export interface SkillFrontmatter {
26
+ name?: string;
27
+ description?: string;
28
+ when_to_use?: string;
29
+ surfaces?: string[];
30
+ }
31
+
32
+ export interface SkillEntry {
33
+ path: string;
34
+ name: string;
35
+ description: string;
36
+ when_to_use?: string;
37
+ surfaces: string[];
38
+ }
39
+
40
+ function toSurfaces(v: unknown): string[] {
41
+ if (typeof v === "string") return [v.trim()].filter(Boolean);
42
+ if (Array.isArray(v)) {
43
+ return v
44
+ .filter((x): x is string => typeof x === "string")
45
+ .map((s) => s.trim())
46
+ .filter(Boolean);
47
+ }
48
+ return [];
49
+ }
50
+
51
+ export function parseFrontmatter(text: string): SkillFrontmatter {
52
+ const m = /^---\r?\n([\s\S]*?)\r?\n---/.exec(text);
53
+ if (!m) return {};
54
+ let data: unknown;
55
+ try {
56
+ data = parseYaml(m[1]);
57
+ } catch {
58
+ return {};
59
+ }
60
+ if (!data || typeof data !== "object") return {};
61
+ const o = data as Record<string, unknown>;
62
+ const fm: SkillFrontmatter = {};
63
+ if (typeof o.name === "string") fm.name = o.name;
64
+ if (typeof o.description === "string") fm.description = o.description;
65
+ if (typeof o.when_to_use === "string") fm.when_to_use = o.when_to_use.trim();
66
+ // `surfaces` is a custom (non-standard) key, so per the Agent-Skills spec it
67
+ // lives under the `metadata` object rather than polluting the top level.
68
+ const metadata =
69
+ o.metadata && typeof o.metadata === "object"
70
+ ? (o.metadata as Record<string, unknown>)
71
+ : undefined;
72
+ fm.surfaces = toSurfaces(metadata?.surfaces);
73
+ return fm;
74
+ }
75
+
76
+ /** Tag-or-all: if any entry is tagged for this surface, keep only those; else keep all. */
77
+ export const selectSkills: (entries: SkillEntry[], surface?: string) => SkillEntry[] =
78
+ selectSurfaceSkills;
79
+
80
+ /** Short stable tag derived from `${url}@${branch}` for the skills-cache directory. */
81
+ export function createSkillsCacheTag(url: string, branch: string): string {
82
+ return crypto.createHash("sha256").update(`${url}@${branch}`).digest("hex").slice(0, 8);
83
+ }
84
+
85
+ /** Parse a github.com repo URL into its owner/repo, or null. */
86
+ export function parseGithubRepo(repoUrl: string): { owner: string; repo: string } | null {
87
+ let parsed: URL;
88
+ try {
89
+ parsed = new URL(repoUrl);
90
+ } catch {
91
+ return null;
92
+ }
93
+ if (parsed.hostname !== "github.com") return null;
94
+ const segs = parsed.pathname.replace(/^\/+|\/+$/g, "").split("/");
95
+ if (segs.length < 2 || !segs[0] || !segs[1]) return null;
96
+ return { owner: segs[0], repo: segs[1].replace(/\.git$/i, "") };
97
+ }
98
+
99
+ /** Resolve a github.com repo URL into its raw.githubusercontent.com base, or null. */
100
+ export function githubRawBase(repoUrl: string, branch: string): string | null {
101
+ const slug = parseGithubRepo(repoUrl);
102
+ if (!slug) return null;
103
+ const cleanBranch = (branch || "main").replace(/^\/+|\/+$/g, "");
104
+ // Reject path traversal in the branch: a git ref never contains "..", and an
105
+ // unescaped (or %2e-escaped) ".." here would walk raw.githubusercontent.com
106
+ // out of the allowlisted owner/repo (e.g. branch "../../other/repo/main").
107
+ let decodedBranch = cleanBranch;
108
+ try {
109
+ decodedBranch = decodeURIComponent(cleanBranch);
110
+ } catch {
111
+ // malformed escape -- fall through to the raw form for the check
112
+ }
113
+ if (decodedBranch.includes("..")) return null;
114
+ return `https://raw.githubusercontent.com/${slug.owner}/${slug.repo}/${cleanBranch}`;
115
+ }
116
+
117
+ /** The on-disk cache dir for a repo: <state dir>/cache/skills/<name>@<hash>/ */
118
+ export function skillsCacheDir(repo: ConfiguredSkillRepo): string {
119
+ const tag = createSkillsCacheTag(repo.url, repo.branch);
120
+ return path.join(resolveStateDir(), "cache", "skills", `${repo.name}@${tag}`);
121
+ }
122
+
123
+ export type FetchSkillResult =
124
+ { ok: true; text: string; cached: boolean } | { ok: false; status?: number; error: string };
125
+
126
+ /**
127
+ * Fetch one file from a skills repo, reading/writing the same on-disk cache the
128
+ * `skills_fetch` tool uses. SKILL.md files use the 1h catalog TTL (they ARE the
129
+ * catalog); everything else (deep reference docs) keeps the 24h content TTL.
130
+ * `cleanPath` must already be normalized (no leading slash, no `..`).
131
+ */
132
+ export async function fetchSkillFile(
133
+ repo: ConfiguredSkillRepo,
134
+ cleanPath: string,
135
+ signal?: AbortSignal,
136
+ force = false,
137
+ ): Promise<FetchSkillResult> {
138
+ const rawBase = githubRawBase(repo.url, repo.branch);
139
+ if (!rawBase) return { ok: false, error: `Repo URL "${repo.url}" is not a GitHub repo URL.` };
140
+
141
+ const cachePath = path.join(skillsCacheDir(repo), cleanPath);
142
+ const ttlMs = cleanPath.endsWith("SKILL.md") ? CATALOG_TTL_MS : 24 * 60 * 60 * 1000;
143
+ if (!force) {
144
+ try {
145
+ const stat = fs.statSync(cachePath);
146
+ if (Date.now() - stat.mtimeMs < ttlMs) {
147
+ return { ok: true, text: fs.readFileSync(cachePath, "utf-8"), cached: true };
148
+ }
149
+ } catch {
150
+ // cache miss -- fall through to fetch
151
+ }
152
+ }
153
+
154
+ // Encode each path segment -- a SKILL.md path could contain URL-significant
155
+ // characters (#, ?) that would otherwise corrupt the request.
156
+ const encodedPath = cleanPath.split("/").map(encodeURIComponent).join("/");
157
+ let response: Response;
158
+ try {
159
+ response = await fetch(`${rawBase}/${encodedPath}`, { signal });
160
+ } catch (e) {
161
+ return { ok: false, error: e instanceof Error ? e.message : String(e) };
162
+ }
163
+ if (!response.ok) return { ok: false, status: response.status, error: `HTTP ${response.status}` };
164
+ const text = await response.text();
165
+ try {
166
+ fs.mkdirSync(path.dirname(cachePath), { recursive: true });
167
+ fs.writeFileSync(cachePath, text, "utf-8");
168
+ } catch (err) {
169
+ console.error("[skills] cache write failed:", err);
170
+ }
171
+ return { ok: true, text, cached: false };
172
+ }
173
+
174
+ /** List every SKILL.md path in a repo via the GitHub trees API. Throws on HTTP failure. */
175
+ export async function treeWalkSkillPaths(
176
+ repo: ConfiguredSkillRepo,
177
+ signal?: AbortSignal,
178
+ ): Promise<string[]> {
179
+ const slug = parseGithubRepo(repo.url);
180
+ if (!slug) return [];
181
+ const api =
182
+ `https://api.github.com/repos/${slug.owner}/${slug.repo}/git/trees/` +
183
+ `${encodeURIComponent(repo.branch)}?recursive=1`;
184
+ const res = await fetch(api, {
185
+ signal,
186
+ headers: { "User-Agent": "loom-skills", Accept: "application/vnd.github+json" },
187
+ });
188
+ if (!res.ok) {
189
+ throw new Error(
190
+ `tree-walk ${slug.owner}/${slug.repo}@${repo.branch} failed: HTTP ${res.status}`,
191
+ );
192
+ }
193
+ const json = (await res.json()) as {
194
+ tree?: Array<{ path?: string; type?: string }>;
195
+ truncated?: boolean;
196
+ };
197
+ if (json.truncated) {
198
+ // GitHub caps recursive trees (~100k entries / 7MB) and returns a partial
199
+ // list. Persisting it would drop SKILL.md paths, and a dropped surface-tagged
200
+ // skill flips selectSkills into tag-or-all. Throw (like a failed file fetch)
201
+ // so refreshCatalog keeps the last-known-good catalog rather than a partial.
202
+ throw new Error(
203
+ `tree-walk ${slug.owner}/${slug.repo}@${repo.branch} was truncated; refusing a partial catalog`,
204
+ );
205
+ }
206
+ const tree = Array.isArray(json.tree) ? json.tree : [];
207
+ return tree
208
+ .filter(
209
+ (n) =>
210
+ n.type === "blob" &&
211
+ typeof n.path === "string" &&
212
+ (n.path === "SKILL.md" || n.path.endsWith("/SKILL.md")),
213
+ )
214
+ .map((n) => n.path as string)
215
+ .sort((a, b) => a.localeCompare(b));
216
+ }
217
+
218
+ /** Walk a repo, fetch+parse each SKILL.md, and return sorted skill entries. */
219
+ export async function discoverCatalog(
220
+ repo: ConfiguredSkillRepo,
221
+ signal?: AbortSignal,
222
+ force = false,
223
+ ): Promise<SkillEntry[]> {
224
+ const paths = await treeWalkSkillPaths(repo, signal);
225
+ // Fetch all SKILL.md files concurrently -- they're independent URLs.
226
+ const results = await Promise.all(paths.map((p) => fetchSkillFile(repo, p, signal, force)));
227
+ const entries: SkillEntry[] = [];
228
+ for (let i = 0; i < paths.length; i++) {
229
+ const res = results[i];
230
+ if (!res.ok) {
231
+ // All-or-nothing: a partial catalog is dangerous. If the files that failed
232
+ // are the surface-tagged ones, selectSkills sees zero tags and falls back
233
+ // to tag-or-all -- surfacing skills that should be hidden. Throw so the
234
+ // caller (refreshCatalog) keeps the last-known-good catalog instead.
235
+ throw new Error(`fetch failed for ${paths[i]}: ${res.error ?? `HTTP ${res.status}`}`);
236
+ }
237
+ const fm = parseFrontmatter(res.text);
238
+ entries.push({
239
+ path: paths[i],
240
+ name: fm.name ?? paths[i],
241
+ description: fm.description ?? "",
242
+ when_to_use: fm.when_to_use,
243
+ surfaces: fm.surfaces ?? [],
244
+ });
245
+ }
246
+ return entries.sort((a, b) => a.path.localeCompare(b.path));
247
+ }
248
+
249
+ export interface SkillCatalog {
250
+ generatedAt: number;
251
+ skills: SkillEntry[];
252
+ }
253
+
254
+ function catalogCachePath(repo: ConfiguredSkillRepo): string {
255
+ return path.join(skillsCacheDir(repo), "_catalog.json");
256
+ }
257
+
258
+ export function readCatalog(repo: ConfiguredSkillRepo): SkillCatalog | null {
259
+ try {
260
+ const data = JSON.parse(fs.readFileSync(catalogCachePath(repo), "utf-8"));
261
+ if (!data || typeof data.generatedAt !== "number" || !Array.isArray(data.skills)) return null;
262
+ return data as SkillCatalog;
263
+ } catch {
264
+ return null;
265
+ }
266
+ }
267
+
268
+ export function writeCatalog(repo: ConfiguredSkillRepo, skills: SkillEntry[]): void {
269
+ try {
270
+ fs.mkdirSync(skillsCacheDir(repo), { recursive: true });
271
+ const payload: SkillCatalog = { generatedAt: Date.now(), skills };
272
+ fs.writeFileSync(catalogCachePath(repo), JSON.stringify(payload, null, 2), "utf-8");
273
+ } catch (err) {
274
+ console.error("[skills] catalog write failed:", err);
275
+ }
276
+ }
277
+
278
+ export function isCatalogStale(cat: SkillCatalog, ttlMs: number = CATALOG_TTL_MS): boolean {
279
+ return Date.now() - cat.generatedAt >= ttlMs;
280
+ }
281
+
282
+ /** Re-walk a repo and rewrite its catalog. Skips the walk if the cache is fresh, unless forced. */
283
+ export async function refreshCatalog(
284
+ repo: ConfiguredSkillRepo,
285
+ opts?: { force?: boolean; signal?: AbortSignal },
286
+ ): Promise<SkillEntry[]> {
287
+ const existing = readCatalog(repo);
288
+ if (!opts?.force && existing && !isCatalogStale(existing)) return existing.skills;
289
+ const skills = await discoverCatalog(repo, opts?.signal, opts?.force);
290
+ writeCatalog(repo, skills);
291
+ return skills;
292
+ }
293
+
294
+ export interface CatalogRefreshResult {
295
+ repo: string;
296
+ count: number;
297
+ ok: boolean;
298
+ error?: string;
299
+ cached?: boolean;
300
+ /** Ships in the package; there was nothing to fetch. */
301
+ bundled?: boolean;
302
+ /** Orbit's staging skills, not a configured repo. */
303
+ staging?: boolean;
304
+ }
305
+
306
+ let warnedShadowedStaging = false;
307
+
308
+ /** The shadowing warning fires once per process; tests that assert it reset it first. */
309
+ export function resetStagingShadowWarning(): void {
310
+ warnedShadowedStaging = false;
311
+ }
312
+
313
+ /**
314
+ * Orbit's staging skills, when this session offers them: the package holds
315
+ * some and no configured repo has taken the name. A configured `orbit` repo
316
+ * wins -- an explicit choice beats the package -- but not quietly. It is not a
317
+ * clean branch preview yet: a live walk of the Orbit repo has no subtree
318
+ * filter, so it lists every loom-tagged SKILL.md in the tree, vendored copies
319
+ * included.
320
+ */
321
+ export function stagingSkillEntries(): SkillEntry[] | null {
322
+ if (!hasBundledContent(STAGING_REPO_NAME)) return null;
323
+ if (findSkillRepo(STAGING_REPO_NAME)) {
324
+ if (!warnedShadowedStaging) {
325
+ warnedShadowedStaging = true;
326
+ console.warn(
327
+ `[skills] a configured repo named "${STAGING_REPO_NAME}" replaces Orbit's staging skills`,
328
+ );
329
+ }
330
+ return null;
331
+ }
332
+ return readBundledCatalog()?.[STAGING_REPO_NAME] ?? [];
333
+ }
334
+
335
+ function stagingSummary(): CatalogRefreshResult[] {
336
+ const entries = stagingSkillEntries();
337
+ if (!entries) return [];
338
+ return [
339
+ { repo: STAGING_REPO_NAME, count: entries.length, ok: true, bundled: true, staging: true },
340
+ ];
341
+ }
342
+
343
+ /** Force-refresh every enabled repo (the manual path). Per-repo errors are reported, not thrown. */
344
+ export async function refreshAllCatalogs(): Promise<CatalogRefreshResult[]> {
345
+ // Repos are independent (separate trees + cache dirs) -- refresh concurrently.
346
+ // Per-repo try/catch so one failure doesn't sink the rest. A bundled repo has
347
+ // nothing to refresh: walking it would report a count the router does not use,
348
+ // and offline it would report a failure for a repo that works.
349
+ const results = await Promise.all(
350
+ listEnabledSkillRepos().map(async (repo): Promise<CatalogRefreshResult> => {
351
+ if (readsFromPackage(repo)) {
352
+ const entries = readBundledCatalog()?.[repo.name];
353
+ return { repo: repo.name, count: entries?.length ?? 0, ok: true, bundled: true };
354
+ }
355
+ try {
356
+ const skills = await refreshCatalog(repo, { force: true });
357
+ return { repo: repo.name, count: skills.length, ok: true };
358
+ } catch (e) {
359
+ return {
360
+ repo: repo.name,
361
+ count: 0,
362
+ ok: false,
363
+ error: e instanceof Error ? e.message : String(e),
364
+ };
365
+ }
366
+ }),
367
+ );
368
+ return [...results, ...stagingSummary()];
369
+ }
370
+
371
+ /**
372
+ * Whether this repo is answered from the package. Config alone is not enough:
373
+ * `isBundledRepo` reads the config, and if the vendored tree is missing -- a
374
+ * packaging regression, a half-finished install -- treating the repo as bundled
375
+ * means an empty router, a background refresh that is skipped, and a manual
376
+ * refresh that reports success without fetching. A session that quietly has no
377
+ * skills and says it is fine. Treat it as live instead and let it recover.
378
+ */
379
+ function readsFromPackage(repo: ConfiguredSkillRepo): boolean {
380
+ return isBundledRepo(repo) && hasBundledContent(repo.name);
381
+ }
382
+
383
+ /**
384
+ * The entries a repo contributes to the router: what shipped in the package if
385
+ * the repo is still pointed at it, otherwise whatever the last walk cached.
386
+ * There is no hand-written third copy any more -- it had drifted from upstream
387
+ * in both directions, listing a skill under a name it no longer had and missing
388
+ * one that had been tagged for months.
389
+ *
390
+ * The last resort is the shipped catalog for a repo we ship that has been
391
+ * pointed somewhere else. Its descriptions are from the pinned commit rather
392
+ * than from that branch, which is a smaller lie than the alternative: deleting
393
+ * the hand-written fallback left a branch-pointed repo with no skills section
394
+ * at all until a background refresh landed, and that refresh only helps the
395
+ * next session.
396
+ */
397
+ export function resolveCatalogEntries(repo: ConfiguredSkillRepo): SkillEntry[] {
398
+ const bundled = readBundledCatalog()?.[repo.name];
399
+ if (readsFromPackage(repo) && bundled?.length) return bundled;
400
+ const cached = readCatalog(repo)?.skills;
401
+ if (cached?.length) return cached;
402
+ return bundled ?? [];
403
+ }
404
+
405
+ /** Current catalog counts without refreshing (the status path). */
406
+ export function catalogSummary(): CatalogRefreshResult[] {
407
+ const configured = listEnabledSkillRepos().map((repo): CatalogRefreshResult => {
408
+ if (readsFromPackage(repo)) {
409
+ const entries = readBundledCatalog()?.[repo.name];
410
+ return { repo: repo.name, count: entries?.length ?? 0, ok: true, bundled: true };
411
+ }
412
+ const cat = readCatalog(repo);
413
+ return { repo: repo.name, count: cat?.skills.length ?? 0, ok: true, cached: cat !== null };
414
+ });
415
+ return [...configured, ...stagingSummary()];
416
+ }
417
+
418
+ /**
419
+ * For each live repo: refresh on start if stale/missing. Errors are swallowed
420
+ * (keep cache). Bundled repos are skipped -- there is nothing to fetch, and a
421
+ * catalog that rewrites itself mid-session would bust the cached system prompt.
422
+ */
423
+ export async function backgroundRefreshSkills(): Promise<void> {
424
+ await Promise.all(
425
+ listEnabledSkillRepos()
426
+ .filter((repo) => !readsFromPackage(repo))
427
+ .map(async (repo) => {
428
+ try {
429
+ await refreshCatalog(repo);
430
+ } catch (err) {
431
+ console.warn(`[skills] background refresh failed for ${repo.name}:`, err);
432
+ }
433
+ }),
434
+ );
435
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Skills-repo accessors. Single site that turns the persisted config
3
+ * into the list the agent actually sees — applies the alpha-time
4
+ * github.com/galaxyproject/* allowlist as a defense-in-depth filter
5
+ * (the renderer already blocks at save time, but a hand-edited
6
+ * `~/.orbit/config.json` shouldn't be able to bypass).
7
+ *
8
+ * Both the `skills_fetch` tool registration (`tools.ts`) and the
9
+ * system-prompt builder (`context.ts`) import from here so the
10
+ * filter is applied uniformly.
11
+ */
12
+
13
+ import { loadConfig } from "./config";
14
+ import { isAllowedSkillUrl } from "../../shared/orbit-config.js";
15
+
16
+ export interface ConfiguredSkillRepo {
17
+ name: string;
18
+ url: string;
19
+ branch: string;
20
+ }
21
+
22
+ /**
23
+ * Conservative slug pattern. The name is later joined into a filesystem path
24
+ * (`~/.loom/cache/skills/<name>/...`); slashes, `..`, and other path-active
25
+ * characters would let a hand-edited config write outside the cache dir.
26
+ * Keep to ASCII letters, digits, dot, dash, underscore.
27
+ */
28
+ const SAFE_NAME_RE = /^[A-Za-z0-9._-]+$/;
29
+
30
+ export function isSafeSkillName(name: string): boolean {
31
+ if (typeof name !== "string" || name.length === 0 || name.length > 64) return false;
32
+ if (name === "." || name === "..") return false;
33
+ return SAFE_NAME_RE.test(name);
34
+ }
35
+
36
+ export function listEnabledSkillRepos(): ConfiguredSkillRepo[] {
37
+ const cfg = loadConfig();
38
+ const repos = (cfg.skills?.repos ?? []) as Array<{
39
+ name?: string;
40
+ url?: string;
41
+ branch?: string;
42
+ enabled?: boolean;
43
+ }>;
44
+ const enabled: ConfiguredSkillRepo[] = [];
45
+ const seenNames = new Set<string>();
46
+ for (const r of repos) {
47
+ if (r?.enabled === false) continue;
48
+ if (typeof r?.name !== "string" || typeof r?.url !== "string") continue;
49
+ // Names key the catalog map and findSkillRepo() lookups, so a duplicate
50
+ // would shadow the earlier repo and mis-route skills_fetch. Keep the first.
51
+ if (seenNames.has(r.name)) {
52
+ console.warn(`[skills] Dropping duplicate repo name "${r.name}" — keeping the first entry`);
53
+ continue;
54
+ }
55
+ if (!isSafeSkillName(r.name)) {
56
+ console.warn(
57
+ `[skills] Dropping repo with unsafe name "${r.name}" — ` +
58
+ `must match /^[A-Za-z0-9._-]+$/ (used as filesystem path)`,
59
+ );
60
+ continue;
61
+ }
62
+ if (!isAllowedSkillUrl(r.url)) {
63
+ console.warn(
64
+ `[skills] Dropping disallowed repo "${r.name}" (${r.url}) — ` +
65
+ `not under github.com/galaxyproject/*`,
66
+ );
67
+ continue;
68
+ }
69
+ enabled.push({
70
+ name: r.name,
71
+ url: r.url,
72
+ branch: typeof r.branch === "string" && r.branch ? r.branch : "main",
73
+ });
74
+ seenNames.add(r.name);
75
+ }
76
+ return enabled;
77
+ }
78
+
79
+ export function findSkillRepo(name: string | undefined): ConfiguredSkillRepo | null {
80
+ const enabled = listEnabledSkillRepos();
81
+ if (enabled.length === 0) return null;
82
+ if (!name) return enabled[0];
83
+ return enabled.find((r) => r.name === name) ?? null;
84
+ }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Catch wasteful SRA fan-out before Galaxy receives any submissions.
3
+ *
4
+ * A completed assistant message contains all sibling calls before tool_call
5
+ * runs. Group only known SRA download wrappers with identical destination and
6
+ * settings. Return an actionable tool error, not a UI approval question.
7
+ * Essential guidance also lives in the system prompt: opaque Python/bash and
8
+ * accessions introduced one at a time cannot be inferred from sibling calls.
9
+ */
10
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
11
+ import path from "node:path";
12
+ import { appendActivityEvent } from "./activity";
13
+ import { getNotebookPath } from "./state";
14
+ import { SraImportGate, type NormalizeName } from "../../shared/sra-import.js";
15
+ import type { GalaxyToolFamily } from "../../shared/galaxy-tool-family.js";
16
+ import { sraImportGuidance } from "../../shared/prompt-blocks.js";
17
+
18
+ export const SRA_IMPORT_GUIDANCE = `${sraImportGuidance()}
19
+ `;
20
+
21
+ // Galaxy's run_tool as the family names it, or as a loom-native galaxy_ tool (any
22
+ // name the family doesn't claim). Names match exactly; unlike the browser's
23
+ // sra-gate normalizer this doesn't trim or lowercase.
24
+ function sraNormalizer(family: GalaxyToolFamily): NormalizeName {
25
+ const strip = (name: string) => family.toolName(name) ?? name.replace(/^galaxy_/, "");
26
+ return (name, args) => ({ name: strip(name), args });
27
+ }
28
+
29
+ function remediation(runs: string[]): string {
30
+ const unique = [...new Set(runs)];
31
+ return (
32
+ "[loom] Batch SRA imports before submission. No job was submitted by this blocked call. " +
33
+ "Use one fastq_dump/fasterq_dump call for all requested, missing accessions with identical settings, " +
34
+ "not one job per accession or a mapped collection. " +
35
+ (unique.length
36
+ ? `Candidate accessions from the blocked calls: ${JSON.stringify(unique.join(","))}. `
37
+ : "") +
38
+ "Exclude verified or running imports first. For the remaining accessions, use a comma-separated " +
39
+ "input|accession string with input|input_select=accession_number, or " +
40
+ 'one text HDA (one accession per line) with input|input_select=file_list and input|file_list={src:"hda",id:<real dataset ID>}. ' +
41
+ "Inspect the installed tool template; retain the extraction settings and use its list:paired output for paired reads. " +
42
+ "Check the history/notebook first so verified or running imports are not repeated. " +
43
+ "Correct the call yourself; do not ask the user to authorize batching or retry the same single-accession calls."
44
+ );
45
+ }
46
+
47
+ export function registerSraImportGate(pi: ExtensionAPI, family: GalaxyToolFamily): void {
48
+ const gate = new SraImportGate({ remediation, normalizeName: sraNormalizer(family) });
49
+ const clear = () => gate.clear();
50
+ pi.on("session_start", clear);
51
+ pi.on("agent_end", clear);
52
+ pi.on("input", clear);
53
+ pi.on("message_end", (event) => {
54
+ if (event.message.role !== "assistant") return;
55
+ gate.observe(event.message.content.flatMap((part) => (part.type === "toolCall" ? [part] : [])));
56
+ });
57
+ pi.on("tool_call", (event) => {
58
+ const blocked = gate.block(event.toolCallId, event.toolName, event.input);
59
+ if (!blocked) return;
60
+ const notebook = getNotebookPath();
61
+ if (notebook) {
62
+ appendActivityEvent(path.dirname(notebook), {
63
+ timestamp: new Date().toISOString(),
64
+ kind: "sra.import.blocked",
65
+ source: "sra-import-gate",
66
+ payload: {
67
+ toolCallId: event.toolCallId,
68
+ historyId: blocked.call.historyId,
69
+ toolId: blocked.call.toolId,
70
+ accessions: blocked.runs,
71
+ cause: blocked.cause,
72
+ },
73
+ });
74
+ }
75
+ return { block: true, reason: blocked.reason };
76
+ });
77
+ }