@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.
- package/CHANGELOG.md +123 -0
- package/LICENSE +21 -0
- package/README.md +760 -5
- package/bin/legacy-mcp-config.js +363 -0
- package/bin/orbit.js +810 -0
- package/bin/pi-extension-path.d.ts +4 -0
- package/bin/pi-extension-path.js +44 -0
- package/bin/provider-auth.d.ts +22 -0
- package/bin/provider-auth.js +77 -0
- package/bin/thinking-pref.js +38 -0
- package/bin/update-check.d.ts +15 -0
- package/bin/update-check.js +137 -0
- package/extensions/cli-update/index.ts +32 -0
- package/extensions/orbit/activity-hooks.ts +141 -0
- package/extensions/orbit/activity.ts +116 -0
- package/extensions/orbit/agent-dir.ts +11 -0
- package/extensions/orbit/auto-resume.ts +352 -0
- package/extensions/orbit/config.ts +3 -0
- package/extensions/orbit/confusables.ts +1 -0
- package/extensions/orbit/context.ts +957 -0
- package/extensions/orbit/dashboard-commands.ts +191 -0
- package/extensions/orbit/dashboard-store.ts +473 -0
- package/extensions/orbit/dashboard-tools.ts +1185 -0
- package/extensions/orbit/empty-completion.ts +99 -0
- package/extensions/orbit/evidence-gate.ts +1276 -0
- package/extensions/orbit/evidence-override-command.ts +294 -0
- package/extensions/orbit/exec-guard/bash-risk.ts +1408 -0
- package/extensions/orbit/exec-guard/gate.ts +181 -0
- package/extensions/orbit/exec-guard/guardian-config.ts +54 -0
- package/extensions/orbit/exec-guard/index.ts +1 -0
- package/extensions/orbit/exec-guard/model-tier.ts +36 -0
- package/extensions/orbit/exec-guard/path-jail.ts +54 -0
- package/extensions/orbit/exec-guard/policy.ts +342 -0
- package/extensions/orbit/exec-guard/runtime-state.ts +15 -0
- package/extensions/orbit/exec-guard/sensitive-read.ts +525 -0
- package/extensions/orbit/exec-guard/types.ts +42 -0
- package/extensions/orbit/execution-commands.ts +134 -0
- package/extensions/orbit/feedback-command.ts +81 -0
- package/extensions/orbit/feedback.ts +96 -0
- package/extensions/orbit/galaxy-api.test.ts +122 -0
- package/extensions/orbit/galaxy-api.ts +606 -0
- package/extensions/orbit/galaxy-artifact-link-guidance.ts +5 -0
- package/extensions/orbit/galaxy-destructive-gate.ts +113 -0
- package/extensions/orbit/galaxy-enrich.ts +1108 -0
- package/extensions/orbit/galaxy-failure.ts +101 -0
- package/extensions/orbit/galaxy-fixture.ts +126 -0
- package/extensions/orbit/galaxy-history-guard.ts +233 -0
- package/extensions/orbit/galaxy-job-block.ts +347 -0
- package/extensions/orbit/galaxy-job-ops.ts +288 -0
- package/extensions/orbit/galaxy-live-source.ts +929 -0
- package/extensions/orbit/galaxy-markdown-adapter.ts +248 -0
- package/extensions/orbit/galaxy-op-policy.ts +332 -0
- package/extensions/orbit/galaxy-ops-tools.ts +326 -0
- package/extensions/orbit/galaxy-output-store.ts +80 -0
- package/extensions/orbit/galaxy-output.ts +346 -0
- package/extensions/orbit/galaxy-page-binding.ts +222 -0
- package/extensions/orbit/galaxy-page-markdown-guidance.ts +15 -0
- package/extensions/orbit/galaxy-page-ops.ts +159 -0
- package/extensions/orbit/galaxy-page-sync.test.ts +417 -0
- package/extensions/orbit/galaxy-page-sync.ts +318 -0
- package/extensions/orbit/galaxy-pages-api.ts +203 -0
- package/extensions/orbit/galaxy-pages-sync.ts +409 -0
- package/extensions/orbit/galaxy-poll-guard.ts +189 -0
- package/extensions/orbit/galaxy-poller.ts +706 -0
- package/extensions/orbit/galaxy-provenance.ts +623 -0
- package/extensions/orbit/galaxy-reconcile.ts +956 -0
- package/extensions/orbit/galaxy-recovery.ts +176 -0
- package/extensions/orbit/galaxy-repeat-guard.ts +55 -0
- package/extensions/orbit/galaxy-submission-capture.ts +707 -0
- package/extensions/orbit/galaxy-submission.ts +502 -0
- package/extensions/orbit/galaxy-tool-source.ts +78 -0
- package/extensions/orbit/galaxy-tool-wrap.ts +234 -0
- package/extensions/orbit/galaxy-udt-block.ts +127 -0
- package/extensions/orbit/galaxy-upload-tus.ts +334 -0
- package/extensions/orbit/galaxy-upload.ts +300 -0
- package/extensions/orbit/galaxy-version-capture.ts +65 -0
- package/extensions/orbit/git.ts +173 -0
- package/extensions/orbit/harness-block-fields.ts +597 -0
- package/extensions/orbit/index.ts +593 -0
- package/extensions/orbit/init-gate.ts +284 -0
- package/extensions/orbit/instructions-command.ts +136 -0
- package/extensions/orbit/invocation-failure-hint.ts +57 -0
- package/extensions/orbit/iwc-plan-check.ts +94 -0
- package/extensions/orbit/lesson-command.ts +303 -0
- package/extensions/orbit/lesson-hint.ts +245 -0
- package/extensions/orbit/lesson-nudge.ts +106 -0
- package/extensions/orbit/lessons/compose.ts +177 -0
- package/extensions/orbit/lessons/counters.ts +120 -0
- package/extensions/orbit/lessons/enabled.ts +116 -0
- package/extensions/orbit/lessons/matcher.ts +346 -0
- package/extensions/orbit/lessons/paths.ts +286 -0
- package/extensions/orbit/lessons/pi-event-contract.ts +105 -0
- package/extensions/orbit/lessons/propose-replay.ts +103 -0
- package/extensions/orbit/lessons/propose-tool.ts +222 -0
- package/extensions/orbit/lessons/propose.ts +502 -0
- package/extensions/orbit/lessons/replay.ts +89 -0
- package/extensions/orbit/lessons/reproduction-index.ts +83 -0
- package/extensions/orbit/lessons/search-tool.ts +99 -0
- package/extensions/orbit/lessons/search.ts +136 -0
- package/extensions/orbit/lessons/store.ts +415 -0
- package/extensions/orbit/lessons/text.ts +36 -0
- package/extensions/orbit/lessons/types.ts +69 -0
- package/extensions/orbit/lessons/user-dir.ts +24 -0
- package/extensions/orbit/lessons/user-lesson.ts +88 -0
- package/extensions/orbit/lessons/wrapper.ts +61 -0
- package/extensions/orbit/lessons-command.ts +147 -0
- package/extensions/orbit/local-exec.ts +39 -0
- package/extensions/orbit/mcp-output.ts +179 -0
- package/extensions/orbit/mcp-servers.test.ts +24 -0
- package/extensions/orbit/mcp-servers.ts +25 -0
- package/extensions/orbit/model-script.ts +351 -0
- package/extensions/orbit/notebook-anchors.ts +342 -0
- package/extensions/orbit/notebook-writer.ts +863 -0
- package/extensions/orbit/observation-allowlists.ts +1109 -0
- package/extensions/orbit/observation-replay.ts +148 -0
- package/extensions/orbit/observation-triggers.ts +563 -0
- package/extensions/orbit/observation-ui.ts +175 -0
- package/extensions/orbit/observations-command.ts +421 -0
- package/extensions/orbit/observations-config.ts +200 -0
- package/extensions/orbit/observations.ts +1381 -0
- package/extensions/orbit/profiles.ts +270 -0
- package/extensions/orbit/progress-updates.ts +95 -0
- package/extensions/orbit/proposal-commands.ts +882 -0
- package/extensions/orbit/provenance-fs-file.ts +59 -0
- package/extensions/orbit/provenance-fs.ts +32 -0
- package/extensions/orbit/provenance-memory-fs.ts +59 -0
- package/extensions/orbit/record-store-file.ts +177 -0
- package/extensions/orbit/record-store-page.ts +77 -0
- package/extensions/orbit/record-store-seam.ts +47 -0
- package/extensions/orbit/record-store.ts +149 -0
- package/extensions/orbit/registry-carrier.ts +107 -0
- package/extensions/orbit/registry-eligibility.ts +95 -0
- package/extensions/orbit/registry-evaluation.ts +403 -0
- package/extensions/orbit/registry-evaluator.ts +519 -0
- package/extensions/orbit/registry-import.ts +91 -0
- package/extensions/orbit/registry-lock.ts +221 -0
- package/extensions/orbit/registry-memory-fs.ts +42 -0
- package/extensions/orbit/registry-page-carrier.ts +103 -0
- package/extensions/orbit/registry-proposal.ts +1348 -0
- package/extensions/orbit/registry-runtime.ts +234 -0
- package/extensions/orbit/registry-schema.ts +735 -0
- package/extensions/orbit/registry-submitter.ts +59 -0
- package/extensions/orbit/registry-templates.ts +346 -0
- package/extensions/orbit/registry.ts +476 -0
- package/extensions/orbit/sandbox/index.ts +120 -0
- package/extensions/orbit/sandbox/sandbox-bash.ts +93 -0
- package/extensions/orbit/sandbox/sandbox-config.ts +87 -0
- package/extensions/orbit/sandbox/sandbox-init-message.ts +28 -0
- package/extensions/orbit/secret-redaction.ts +247 -0
- package/extensions/orbit/session-index/cwd.ts +18 -0
- package/extensions/orbit/session-index/db.ts +56 -0
- package/extensions/orbit/session-index/indexer.ts +154 -0
- package/extensions/orbit/session-index/is-enabled.ts +17 -0
- package/extensions/orbit/session-index/parse.ts +254 -0
- package/extensions/orbit/session-index/query.ts +209 -0
- package/extensions/orbit/session-index/schema.ts +72 -0
- package/extensions/orbit/session-index/tools.ts +152 -0
- package/extensions/orbit/session-lifecycle.ts +321 -0
- package/extensions/orbit/skill-triggers.ts +159 -0
- package/extensions/orbit/skills-command.ts +48 -0
- package/extensions/orbit/skills-discovery.ts +435 -0
- package/extensions/orbit/skills.ts +84 -0
- package/extensions/orbit/sra-import-gate.ts +77 -0
- package/extensions/orbit/state.ts +265 -0
- package/extensions/orbit/submission-replay.ts +147 -0
- package/extensions/orbit/sync-command.ts +157 -0
- package/extensions/orbit/teams/critic-parser.ts +93 -0
- package/extensions/orbit/teams/dispatcher.ts +210 -0
- package/extensions/orbit/teams/is-enabled.ts +22 -0
- package/extensions/orbit/teams/tool.ts +187 -0
- package/extensions/orbit/teams/types.ts +57 -0
- package/extensions/orbit/teams/validate.ts +42 -0
- package/extensions/orbit/tester-id-command.ts +133 -0
- package/extensions/orbit/tools-sync.ts +279 -0
- package/extensions/orbit/tools.ts +1300 -0
- package/extensions/orbit/types.ts +41 -0
- package/extensions/orbit/ui-bridge.ts +55 -0
- package/extensions/orbit/ulid.ts +60 -0
- package/extensions/orbit/user-instructions.ts +388 -0
- package/extensions/orbit/vendor/skills/_catalog.json +68 -0
- package/extensions/orbit/vendor/skills/_manifest.json +1106 -0
- package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/SKILL.md +112 -0
- package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/_provenance.json +218 -0
- package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/_required_tools.json +33 -0
- package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/_verify.json +4 -0
- package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/add.json +50 -0
- package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/draft-extract.json +51 -0
- package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/draft-next-step.json +42 -0
- package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/draft-validate.json +140 -0
- package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/list.json +32 -0
- package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/notes/galaxy-tool-job-failure-reference.md +137 -0
- package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/notes/open-requirements-ledger.md +173 -0
- package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/schemas/galaxy-tool-summary.schema.json +175 -0
- package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/schemas/galaxy-workflow-draft.schema.json +2727 -0
- package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/SKILL.md +82 -0
- package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/_provenance.json +133 -0
- package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/_required_tools.json +16 -0
- package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/_verify.json +4 -0
- package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/references/cli/draft-validate.json +140 -0
- package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/references/notes/galaxy-workflow-draft-format.md +135 -0
- package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/references/notes/open-requirements-ledger.md +173 -0
- package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/references/schemas/galaxy-workflow-draft.schema.json +2727 -0
- package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/SKILL.md +84 -0
- package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/_provenance.json +166 -0
- package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/_verify.json +29 -0
- package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/galaxy-workflow-testability-design.md +136 -0
- package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/iwc-shortcuts-anti-patterns.md +357 -0
- package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/iwc-test-data-conventions.md +308 -0
- package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/planemo-asserts-idioms.md +246 -0
- package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/planemo-workflow-test-architecture.md +151 -0
- package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/schemas/galaxy-workflow-test-plan.schema.json +552 -0
- package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/schemas/summary-galaxy-workflow.schema.json +687 -0
- package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/schemas/tests-format.schema.json +7328 -0
- package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/SKILL.md +127 -0
- package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/_provenance.json +198 -0
- package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/_required_tools.json +16 -0
- package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/_verify.json +4 -0
- package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/cli/convert.json +123 -0
- package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/notes/galaxy-data-flow-draft-contract.md +129 -0
- package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/notes/iwc-shortcuts-anti-patterns.md +357 -0
- package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/notes/iwc-test-data-conventions.md +308 -0
- package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/notes/open-requirements-ledger.md +173 -0
- package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/SKILL.md +73 -0
- package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/_provenance.json +160 -0
- package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/_verify.json +4 -0
- package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/galaxy-collection-semantics.md +43 -0
- package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/galaxy-collection-semantics.yml +1250 -0
- package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/galaxy-tool-job-failure-reference.md +137 -0
- package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/galaxy-workflow-invocation-failure-reference.md +138 -0
- package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/iwc-shortcuts-anti-patterns.md +357 -0
- package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/nextflow-operators-to-galaxy-collection-recipes.md +98 -0
- package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/planemo-asserts-idioms.md +246 -0
- package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/planemo-workflow-test-architecture.md +151 -0
- package/extensions/orbit/vendor/skills/discover-shed-tool/SKILL.md +174 -0
- package/extensions/orbit/vendor/skills/discover-shed-tool/_provenance.json +130 -0
- package/extensions/orbit/vendor/skills/discover-shed-tool/_required_tools.json +18 -0
- package/extensions/orbit/vendor/skills/discover-shed-tool/_verify.json +17 -0
- package/extensions/orbit/vendor/skills/discover-shed-tool/references/cli/tool-revisions.json +48 -0
- package/extensions/orbit/vendor/skills/discover-shed-tool/references/cli/tool-search.json +95 -0
- package/extensions/orbit/vendor/skills/discover-shed-tool/references/cli/tool-versions.json +39 -0
- package/extensions/orbit/vendor/skills/discover-shed-tool/references/notes/component-tool-shed-search.md +230 -0
- package/extensions/orbit/vendor/skills/discover-shed-tool/references/schemas/galaxy-tool-discovery.schema.json +231 -0
- package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/SKILL.md +93 -0
- package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/_provenance.json +201 -0
- package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/_required_tools.json +28 -0
- package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/_verify.json +17 -0
- package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/cli/planemo.md +44 -0
- package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/cli/validate-tests.json +40 -0
- package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/galaxy-workflow-testability-design.md +136 -0
- package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/iwc-shortcuts-anti-patterns.md +357 -0
- package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/iwc-test-data-conventions.md +308 -0
- package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/planemo-asserts-idioms.md +246 -0
- package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/planemo-workflow-test-architecture.md +151 -0
- package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/schemas/galaxy-workflow-test-plan.schema.json +552 -0
- package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/schemas/tests-format.schema.json +7328 -0
- package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/SKILL.md +81 -0
- package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/_provenance.json +93 -0
- package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/_verify.json +17 -0
- package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/references/notes/open-requirements-ledger.md +173 -0
- package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/references/schemas/summary-galaxy-workflow.schema.json +687 -0
- package/extensions/orbit/vendor/skills/pipeline-update-interview-to-galaxy/SKILL.md +81 -0
- package/extensions/orbit/vendor/skills/pipeline-update-interview-to-galaxy/_assembly.json +23 -0
- package/extensions/orbit/vendor/skills/run-workflow-test/SKILL.md +79 -0
- package/extensions/orbit/vendor/skills/run-workflow-test/_provenance.json +125 -0
- package/extensions/orbit/vendor/skills/run-workflow-test/_required_tools.json +28 -0
- package/extensions/orbit/vendor/skills/run-workflow-test/_verify.json +4 -0
- package/extensions/orbit/vendor/skills/run-workflow-test/references/cli/planemo.md +44 -0
- package/extensions/orbit/vendor/skills/run-workflow-test/references/cli/validate-tests.json +40 -0
- package/extensions/orbit/vendor/skills/run-workflow-test/references/notes/galaxy-workflow-invocation-failure-reference.md +138 -0
- package/extensions/orbit/vendor/skills/run-workflow-test/references/notes/planemo-asserts-idioms.md +246 -0
- package/extensions/orbit/vendor/skills/run-workflow-test/references/notes/planemo-workflow-test-architecture.md +151 -0
- package/extensions/orbit/vendor/skills/run-workflow-test/references/schemas/tests-format.schema.json +7328 -0
- package/extensions/orbit/vendor/skills/skills/LICENSE +21 -0
- package/extensions/orbit/vendor/skills/skills/collection-manipulation/README.md +39 -0
- package/extensions/orbit/vendor/skills/skills/collection-manipulation/SKILL.md +892 -0
- package/extensions/orbit/vendor/skills/skills/collection-manipulation/references/api-patterns.md +927 -0
- package/extensions/orbit/vendor/skills/skills/collection-manipulation/references/apply-rules.md +1482 -0
- package/extensions/orbit/vendor/skills/skills/collection-manipulation/references/test-patterns.md +996 -0
- package/extensions/orbit/vendor/skills/skills/collection-manipulation/references/tools.md +609 -0
- package/extensions/orbit/vendor/skills/skills/galaxy-data-libraries/SKILL.md +170 -0
- package/extensions/orbit/vendor/skills/skills/galaxy-integration/README.md +162 -0
- package/extensions/orbit/vendor/skills/skills/galaxy-integration/SKILL.md +99 -0
- package/extensions/orbit/vendor/skills/skills/galaxy-integration/examples/README.md +119 -0
- package/extensions/orbit/vendor/skills/skills/galaxy-integration/examples/tool-checking.md +419 -0
- package/extensions/orbit/vendor/skills/skills/galaxy-integration/examples/workflow-testing.md +617 -0
- package/extensions/orbit/vendor/skills/skills/galaxy-integration/galaxy-integration.md +614 -0
- package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/SKILL.md +144 -0
- package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/examples/average_col3.ipynb +68 -0
- package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/examples/extract_sample_metadata.ipynb +190 -0
- package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/examples/variant_annotation.ipynb +816 -0
- package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/examples/vcp_variant_map.ipynb +443 -0
- package/extensions/orbit/vendor/skills/skills/galaxy-integration/scripts/README.md +165 -0
- package/extensions/orbit/vendor/skills/skills/galaxy-integration/scripts/galaxy_tool_checker.py +521 -0
- package/extensions/orbit/vendor/skills/skills/galaxy-mcp-reference/SKILL.md +128 -0
- package/extensions/orbit/vendor/skills/skills/galaxy-mcp-reference/gotchas.md +135 -0
- package/extensions/orbit/vendor/skills/skills/galaxy-mcp-reference/history-access.md +132 -0
- package/extensions/orbit/vendor/skills/skills/reproduciblify/SKILL.md +146 -0
- package/extensions/orbit/vendor/skills/skills/reproduciblify/references/directives.yml +496 -0
- package/extensions/orbit/vendor/skills/skills/udt-authoring/SKILL.md +245 -0
- package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/01-minimal-echo.yml +27 -0
- package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/02-single-data-in-out.yml +27 -0
- package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/03-multiple-data-js.yml +28 -0
- package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/04-select-integer-boolean.yml +41 -0
- package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/05-resource-requirements.yml +25 -0
- package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/06-biocontainer-tool.yml +38 -0
- package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/07-inline-python-script.yml +56 -0
- package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/08-configfile-script.yml +74 -0
- package/extensions/orbit/vendor/skills/skills/udt-authoring/references/common-mistakes.md +76 -0
- package/extensions/orbit/vendor/skills/skills/udt-authoring/references/schema-reference.md +155 -0
- package/extensions/orbit/vendor/skills/skills/udt-authoring/references/templating.md +196 -0
- package/extensions/orbit/vendor/skills/skills/udt-authoring/scripts/validate.py +109 -0
- package/extensions/orbit/vendor/skills/skills/workflow-reports/README.md +71 -0
- package/extensions/orbit/vendor/skills/skills/workflow-reports/SKILL.md +190 -0
- package/extensions/orbit/vendor/skills/skills/workflow-reports/examples/histology-staining.md +145 -0
- package/extensions/orbit/vendor/skills/skills/workflow-reports/examples/tissue-microarray-analysis.md +176 -0
- package/extensions/orbit/vendor/skills/skills/workflow-reports/references/directives.md +415 -0
- package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/SKILL.md +98 -0
- package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/_provenance.json +93 -0
- package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/_required_tools.json +28 -0
- package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/_verify.json +17 -0
- package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/references/cli/convert.json +123 -0
- package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/references/cli/foundry.md +25 -0
- package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/references/cli/validate.json +142 -0
- package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/references/schemas/summary-galaxy-workflow.schema.json +687 -0
- package/extensions/orbit/vendor/skills/validate-galaxy-workflow/SKILL.md +74 -0
- package/extensions/orbit/vendor/skills/validate-galaxy-workflow/_provenance.json +71 -0
- package/extensions/orbit/vendor/skills/validate-galaxy-workflow/_required_tools.json +16 -0
- package/extensions/orbit/vendor/skills/validate-galaxy-workflow/_verify.json +4 -0
- package/extensions/orbit/vendor/skills/validate-galaxy-workflow/references/cli/validate.json +142 -0
- package/extensions/orbit/vendor/skills/validate-galaxy-workflow/references/notes/galaxy-workflow-invocation-failure-reference.md +138 -0
- package/extensions/orbit/vendor/skills/validate-galaxy-workflow/references/notes/galaxy-workflow-testability-design.md +136 -0
- package/extensions/orbit/vendor-skills.ts +283 -0
- package/extensions/orbit/workspace-state-dir.ts +46 -0
- package/extensions/orbit-handoff/index.ts +73 -0
- package/extensions/orbit-handoff/orbit-launcher.ts +142 -0
- package/extensions/whats-new/index.ts +98 -0
- package/lessons/LICENSE +17 -0
- package/lessons/README.md +117 -0
- package/lessons/SCHEMA.md +187 -0
- package/lessons/build-snapshot.mjs +311 -0
- package/lessons/data/downloaded-file-is-not-what-its-extension-says.md +61 -0
- package/lessons/galaxy-api/403-history-is-a-hard-stop.md +57 -0
- package/lessons/galaxy-api/collection-into-single-dataset-input.md +61 -0
- package/lessons/galaxy-api/connectedvalue-in-command-line.md +62 -0
- package/lessons/galaxy-api/hid-is-not-an-id.md +59 -0
- package/lessons/galaxy-api/invoke-workflow-inputs-not-params.md +60 -0
- package/lessons/galaxy-api/repeat-param-pipe-keys.md +63 -0
- package/lessons/galaxy-api/run-tool-returns-on-submit.md +61 -0
- package/lessons/galaxy-tools/reference-index-not-on-server.md +62 -0
- package/lessons/log.md +42 -0
- package/lessons/reproduction/input-population-mismatch.md +59 -0
- package/lessons/reproduction/methods-text-vs-executed-parameters.md +62 -0
- package/lessons/snapshot.json +1004 -0
- package/lessons/stats/de-contrast-direction-and-sample-labels.md +63 -0
- package/lessons/stats/na-coerced-to-zero-in-filters.md +59 -0
- package/lessons/validate.mjs +1219 -0
- package/package.json +103 -5
- package/shared/agent-prompt.d.ts +8 -0
- package/shared/agent-prompt.js +15 -0
- package/shared/approval-prompt.d.ts +4 -0
- package/shared/approval-prompt.js +61 -0
- package/shared/brain-env.d.ts +14 -0
- package/shared/brain-env.js +108 -0
- package/shared/brain-exit.d.ts +20 -0
- package/shared/brain-exit.js +149 -0
- package/shared/capability-profile.d.ts +16 -0
- package/shared/capability-profile.js +75 -0
- package/shared/config-source.d.ts +13 -0
- package/shared/config-source.js +17 -0
- package/shared/confusables.d.ts +3 -0
- package/shared/confusables.js +93 -0
- package/shared/custom-provider.d.ts +45 -0
- package/shared/custom-provider.js +169 -0
- package/shared/dashboard-contract.d.ts +123 -0
- package/shared/dashboard-contract.js +560 -0
- package/shared/dashboard-layout-store.d.ts +44 -0
- package/shared/dashboard-layout-store.js +281 -0
- package/shared/feedback-contract.d.ts +61 -0
- package/shared/feedback-contract.js +146 -0
- package/shared/galaxy-artifact-links.d.ts +30 -0
- package/shared/galaxy-artifact-links.js +166 -0
- package/shared/galaxy-credentials.d.ts +26 -0
- package/shared/galaxy-credentials.js +71 -0
- package/shared/galaxy-destructive.d.ts +21 -0
- package/shared/galaxy-destructive.js +269 -0
- package/shared/galaxy-guidance.d.ts +2 -0
- package/shared/galaxy-guidance.js +53 -0
- package/shared/galaxy-live-contract.d.ts +92 -0
- package/shared/galaxy-live-contract.js +180 -0
- package/shared/galaxy-page-cells.d.ts +2 -0
- package/shared/galaxy-page-cells.js +22 -0
- package/shared/galaxy-tool-family.d.ts +5 -0
- package/shared/galaxy-tool-family.js +27 -0
- package/shared/galaxy-url.d.ts +1 -0
- package/shared/galaxy-url.js +48 -0
- package/shared/gtn.d.ts +31 -0
- package/shared/gtn.js +253 -0
- package/shared/handled-prompt.d.ts +3 -0
- package/shared/handled-prompt.js +26 -0
- package/shared/known-provider.d.ts +11 -0
- package/shared/known-provider.js +89 -0
- package/shared/lesson-hint-marker.d.ts +7 -0
- package/shared/lesson-hint-marker.js +32 -0
- package/shared/lesson-rules.d.ts +150 -0
- package/shared/lesson-rules.js +203 -0
- package/shared/malformed-object-ids.d.ts +1 -0
- package/shared/malformed-object-ids.js +37 -0
- package/shared/markdown-sections.d.ts +10 -0
- package/shared/markdown-sections.js +118 -0
- package/shared/notebook-fences.d.ts +12 -0
- package/shared/notebook-fences.js +53 -0
- package/shared/observation-contract.d.ts +91 -0
- package/shared/observation-contract.js +544 -0
- package/shared/orbit-config.d.ts +226 -0
- package/shared/orbit-config.js +189 -0
- package/shared/orbit-env.d.ts +13 -0
- package/shared/orbit-env.js +124 -0
- package/shared/orbit-shell-contract.d.ts +74 -0
- package/shared/orbit-shell-contract.js +30 -0
- package/shared/page-content-hash.d.ts +1 -0
- package/shared/page-content-hash.js +13 -0
- package/shared/pi-default-model.d.ts +7 -0
- package/shared/pi-default-model.js +41 -0
- package/shared/prompt-blocks.d.ts +87 -0
- package/shared/prompt-blocks.js +898 -0
- package/shared/provider-auth-caps.d.ts +22 -0
- package/shared/provider-auth-caps.js +57 -0
- package/shared/random.d.ts +2 -0
- package/shared/random.js +15 -0
- package/shared/record-excerpt.d.ts +4 -0
- package/shared/record-excerpt.js +16 -0
- package/shared/redirect-guard.d.ts +36 -0
- package/shared/redirect-guard.js +235 -0
- package/shared/skills-pin.d.ts +8 -0
- package/shared/skills-pin.js +9 -0
- package/shared/skills-router.d.ts +17 -0
- package/shared/skills-router.js +63 -0
- package/shared/sra-import.d.ts +34 -0
- package/shared/sra-import.js +206 -0
- package/shared/state-dir.d.ts +21 -0
- package/shared/state-dir.js +240 -0
- package/shared/team-dispatch-contract.d.ts +28 -0
- package/shared/team-dispatch-contract.js +1 -0
- package/shared/truncate-middle.d.ts +11 -0
- package/shared/truncate-middle.js +68 -0
- package/shared/version-compare.d.ts +10 -0
- package/shared/version-compare.js +74 -0
- package/shared/whats-new.d.ts +31 -0
- package/shared/whats-new.js +83 -0
- package/shared/wsl.d.ts +10 -0
- 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
|
+
}
|