@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,117 @@
|
|
|
1
|
+
# Lessons
|
|
2
|
+
|
|
3
|
+
A lesson records one observed, scoped thing: _in this situation this goes wrong,
|
|
4
|
+
here is how to tell it is this one, here is what to do, and here is how to know
|
|
5
|
+
it worked._ It is not a skill. A skill is authored, prescriptive and broad; a
|
|
6
|
+
lesson is a note from a specific failure that nobody wrote down the first time.
|
|
7
|
+
|
|
8
|
+
The corpus is deliberately small. Most knowledge belongs somewhere else, and the
|
|
9
|
+
sorting rule below is about sending it there.
|
|
10
|
+
|
|
11
|
+
## The sorting rule
|
|
12
|
+
|
|
13
|
+
Before writing a lesson, ask what the knowledge is. Exactly one destination:
|
|
14
|
+
|
|
15
|
+
| What it is | Where it goes |
|
|
16
|
+
| ---------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
17
|
+
| Already in a GTN FAQ, tutorial or forum thread | Cite that. No lesson. |
|
|
18
|
+
| Already a lesson here | Add evidence to the existing one -- counts, versions, another `sources` entry. No new lesson. |
|
|
19
|
+
| Something a validator, a schema or a better error message would catch | An issue on galaxy-mcp, the Foundry, or Galaxy. Never the corpus. |
|
|
20
|
+
| A general how-to | A GTN FAQ pull request. Regular docs are the default landing. |
|
|
21
|
+
| Agent misbehaviour | The Orbit prompt plus an eval. Not knowledge. |
|
|
22
|
+
| A silent scientific pitfall, an expectation, a choice, a source quirk, or a reproduction note, with no hit above | A lesson here. |
|
|
23
|
+
|
|
24
|
+
The last row is the whole corpus. If a lesson would be better as an error
|
|
25
|
+
message, write the error message.
|
|
26
|
+
|
|
27
|
+
## Namespaces
|
|
28
|
+
|
|
29
|
+
The namespace is the first path segment and part of the lesson's id, so
|
|
30
|
+
`stats/na-coerced-to-zero-in-filters.md` has the id
|
|
31
|
+
`stats/na-coerced-to-zero-in-filters`.
|
|
32
|
+
|
|
33
|
+
- `stats` -- statistical reasoning and interpretation.
|
|
34
|
+
- `reproduction` -- reproducing a published analysis.
|
|
35
|
+
- `data` -- acquiring data and what the source actually hands back.
|
|
36
|
+
- `galaxy-tools` -- a tool or a server's configuration of it.
|
|
37
|
+
- `galaxy-api` -- lessons whose durable fix now lives somewhere else. Kept for
|
|
38
|
+
the record, never surfaced: a non-empty `graduated_to` is what makes that
|
|
39
|
+
true, and the validator requires one in this namespace.
|
|
40
|
+
|
|
41
|
+
## Layout
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
lessons/
|
|
45
|
+
README.md SCHEMA.md LICENSE log.md
|
|
46
|
+
validate.mjs build-snapshot.mjs snapshot.json
|
|
47
|
+
<namespace>/<slug>.md
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`snapshot.json` is generated and committed. Never hand-edit it: run
|
|
51
|
+
`npm run build:lessons` and commit the result. `npm run check:lessons` validates
|
|
52
|
+
every lesson and fails if the snapshot is out of date, and runs in CI.
|
|
53
|
+
|
|
54
|
+
## Writing one
|
|
55
|
+
|
|
56
|
+
`SCHEMA.md` is the field list. The things that actually decide whether a lesson
|
|
57
|
+
earns its place:
|
|
58
|
+
|
|
59
|
+
- **The title is the situation, not the fix.** "Numeric filters treat NA as 0"
|
|
60
|
+
rather than "Always exclude NA".
|
|
61
|
+
- **`Check first` and `Validate` are required, and are the point.** The first
|
|
62
|
+
keeps the lesson from being applied to a situation that merely looks similar.
|
|
63
|
+
The second keeps "the error went away" from passing as success.
|
|
64
|
+
- **Cause is optional and labelled.** Recovering from something is not proof you
|
|
65
|
+
diagnosed it. Say `hypothesized` when it is a hypothesis.
|
|
66
|
+
- **Evidence, editorial status and applicability are three separate axes.**
|
|
67
|
+
`evidence.{symptom,cause,outcome}` each carry their own label and a `method`;
|
|
68
|
+
`status` is editorial; `applies_to.versions` is scope. There is no single
|
|
69
|
+
confidence score and nothing is promoted automatically.
|
|
70
|
+
- **Triggers are machine-matchable or they are decoration.** Literal normalized
|
|
71
|
+
signatures, tool ids, `galaxy_*` MCP tool names, datatypes, bare hostnames,
|
|
72
|
+
dotted extensions, lowercase plan-step keywords. The prose `cues` field is for
|
|
73
|
+
humans and is never matched. A lesson with every trigger list empty is
|
|
74
|
+
rejected.
|
|
75
|
+
- **An upstream fix narrows `applies_to.versions`.** It does not retire the
|
|
76
|
+
lesson -- older installs still hit it.
|
|
77
|
+
- **`stale_after` is required.** A lesson that nobody will re-verify should drop
|
|
78
|
+
out on its own.
|
|
79
|
+
|
|
80
|
+
The body carries nothing to follow and nothing to run: no URLs, no markdown
|
|
81
|
+
links, images or HTML, no code blocks, printable ASCII only, each section at
|
|
82
|
+
most 600 characters. Those are enforced, not advisory. Provenance goes in
|
|
83
|
+
`sources`, and a link there must point at one of the hosts listed in
|
|
84
|
+
`LINK_HOSTS` in `validate.mjs`.
|
|
85
|
+
|
|
86
|
+
## Contributing
|
|
87
|
+
|
|
88
|
+
1. Fork, branch, add one `.md` file under the right namespace.
|
|
89
|
+
2. `npm run check:lessons` -- it prints `path:line: message` for every problem.
|
|
90
|
+
3. `npm run build:lessons` and commit `lessons/snapshot.json` alongside.
|
|
91
|
+
4. Add a line to `log.md`.
|
|
92
|
+
5. Open a pull request against `main`.
|
|
93
|
+
|
|
94
|
+
Your pull request needs both of these, checked by you:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
- [ ] This lesson contains no personal data and no research data. No filesystem
|
|
98
|
+
paths, dataset or history ids, URLs, private server hostnames, dataset,
|
|
99
|
+
history, sample or account names, and no values copied out of anyone's
|
|
100
|
+
data -- mine or anybody else's.
|
|
101
|
+
- [ ] Signed-off-by line present (Developer Certificate of Origin 1.1), and I
|
|
102
|
+
am licensing this lesson under CC BY 4.0 as described in LICENSE.
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Sign off with `git commit -s`, which appends
|
|
106
|
+
`Signed-off-by: Your Name <you@example.com>`. That line is the Developer
|
|
107
|
+
Certificate of Origin 1.1 assertion: you wrote the contribution, or have the
|
|
108
|
+
right to submit it under the licence above.
|
|
109
|
+
|
|
110
|
+
The validator is the second line of defence on the first checkbox, not the
|
|
111
|
+
first. It refuses the shapes of URLs, links, HTML, paths, ids, addresses and
|
|
112
|
+
keys and caps every field, but it cannot tell that a plausible-looking tool id
|
|
113
|
+
was a private server's, that a sentence describes one specific person's data,
|
|
114
|
+
or that a sentence is an instruction aimed at the model rather than advice. That judgement is yours, and a
|
|
115
|
+
published lesson cannot be unpublished from git history -- the privacy decision
|
|
116
|
+
happens before the pull request, which is why the checkbox is phrased the way
|
|
117
|
+
it is.
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Lesson schema v1
|
|
2
|
+
|
|
3
|
+
The file format. `validate.mjs` is the authoritative version of all of this:
|
|
4
|
+
where this document and that script disagree, the script wins and this document
|
|
5
|
+
is wrong. Run `npm run check:lessons`.
|
|
6
|
+
|
|
7
|
+
One markdown file per lesson at `lessons/<namespace>/<slug>.md`. The id is the
|
|
8
|
+
path minus `.md`, e.g. `stats/na-coerced-to-zero-in-filters`. The slug is
|
|
9
|
+
lowercase words joined by hyphens, at most 80 characters.
|
|
10
|
+
|
|
11
|
+
The format is Google Cloud's Open Knowledge Format: a directory of markdown with
|
|
12
|
+
YAML frontmatter, distributed as a git repository. OKF fields come first; Orbit's
|
|
13
|
+
extension fields come after.
|
|
14
|
+
|
|
15
|
+
## Frontmatter
|
|
16
|
+
|
|
17
|
+
```yaml
|
|
18
|
+
type: Lesson # OKF required
|
|
19
|
+
title: string # <= 120 chars; the situation, not the fix
|
|
20
|
+
description: string # <= 200 chars, one line
|
|
21
|
+
tags: [string] # free; stage and formats are mirrored here by the build
|
|
22
|
+
status: draft | stable | deprecated # OKF
|
|
23
|
+
generated: { by: string, at: string } # e.g. "agent:loom/0.6.0" or "human:loom-maintainers"
|
|
24
|
+
verified: [{ by: string, at: string }] # optional; by = "human:<pseudonym>", never a contributor id
|
|
25
|
+
stale_after: string # ISO date; required
|
|
26
|
+
sources: [{ id: string, resource?: string, title?: string }] # provenance; required when derived from GTN/forum
|
|
27
|
+
|
|
28
|
+
kind: pitfall | expectation | choice | source-quirk | reproduction
|
|
29
|
+
stage:
|
|
30
|
+
[
|
|
31
|
+
data-acquisition | metadata-reconciliation | tool-parameterization | job-execution | result-interpretation,
|
|
32
|
+
]
|
|
33
|
+
trigger:
|
|
34
|
+
signatures: [string] # literal, normalized, each <= 200
|
|
35
|
+
tools: [string] # Galaxy tool ids or families
|
|
36
|
+
mcp_tools: [string] # galaxy_* names
|
|
37
|
+
formats: [string] # datatypes / extensions
|
|
38
|
+
hosts: [string] # hostnames seen in URLs/commands, e.g. "ncbi.nlm.nih.gov"
|
|
39
|
+
extensions: [string] # file extensions seen in args, e.g. ".gtf"
|
|
40
|
+
step_keywords: [string] # lowercase words matched against plan-step text
|
|
41
|
+
cues: string # human-readable description of when this applies (not matched)
|
|
42
|
+
applies_to: { versions: string, tested: string }
|
|
43
|
+
evidence:
|
|
44
|
+
symptom: verified | reported
|
|
45
|
+
cause: verified | hypothesized | unknown
|
|
46
|
+
outcome: validated | unvalidated
|
|
47
|
+
method: string
|
|
48
|
+
graduated_to: [string] # free text or links; non-empty => not surfaced by the matcher
|
|
49
|
+
upstream: [string]
|
|
50
|
+
supersedes: [string] # lesson ids
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Body
|
|
54
|
+
|
|
55
|
+
Exactly these `##` sections, in this order. `Cause` is optional; the rest are
|
|
56
|
+
required.
|
|
57
|
+
|
|
58
|
+
`Symptom`, `Cause`, `Check first`, `Intervention`, `Validate`,
|
|
59
|
+
`Does NOT apply when`.
|
|
60
|
+
|
|
61
|
+
Each section is at most 600 characters and must not be empty. Nothing before
|
|
62
|
+
the first heading. No fenced code blocks anywhere on a line, and no indented
|
|
63
|
+
code blocks, at any depth (a short inline backtick span is fine). No URLs of
|
|
64
|
+
any scheme, protocol-relative, scheme-less or `www.`, anywhere in the body. No
|
|
65
|
+
heading other than those six, whether `#`-style at any indent or a setext
|
|
66
|
+
underline, and no horizontal rules. The whole file is at most 16384 bytes.
|
|
67
|
+
|
|
68
|
+
The body and every frontmatter string are also run through `marked`'s GFM lexer,
|
|
69
|
+
so "is this a link" is answered the way a renderer answers it rather than by a
|
|
70
|
+
line regex. Refused at any depth (inside blockquotes, list items and tables
|
|
71
|
+
too): links of every kind (inline, reference, autolinks), link reference
|
|
72
|
+
definitions, images, HTML, backslash escapes and character references
|
|
73
|
+
(`@`, `@`, `&`). A code span may show a placeholder such as
|
|
74
|
+
`<collection id>`, but not a tag with attributes, a closing tag, a link, a nested
|
|
75
|
+
code span hiding either, or an element like `<script>` or `<iframe>` that is
|
|
76
|
+
live even bare. The placeholders `normalizeSignature` writes (`<path>`, `<id>`,
|
|
77
|
+
`<url>`, `<n>`, `<email>`) are text anywhere. A string longer than the file cap
|
|
78
|
+
is refused unchecked.
|
|
79
|
+
|
|
80
|
+
## What the validator adds on top of the field list
|
|
81
|
+
|
|
82
|
+
The contract names the fields; these are the rules the validator applies to
|
|
83
|
+
them, and they are part of the schema.
|
|
84
|
+
|
|
85
|
+
- **Unknown keys are rejected**, at the top level and inside `generated`,
|
|
86
|
+
`verified[]`, `sources[]`, `trigger`, `applies_to` and `evidence`. Every
|
|
87
|
+
required key must be present; `verified` is the only optional one.
|
|
88
|
+
- **Printable ASCII only, in the whole file and in every parsed value.** A
|
|
89
|
+
Unicode em-dash, a smart quote or a non-breaking space is an error, reported
|
|
90
|
+
by codepoint. Write `--`. Parsed values are checked too, so a YAML escape like
|
|
91
|
+
`"\u202e"` cannot carry a control character past the file check.
|
|
92
|
+
- **Plain YAML only.** No comments (they ship in the raw file and would
|
|
93
|
+
otherwise go unchecked), no anchors or aliases, no explicit tags.
|
|
94
|
+
- **Nothing identifying, anywhere.** No absolute or home-directory paths,
|
|
95
|
+
Windows or UNC paths, hex ids of 16 or more characters, uuids, IPv4 or IPv6
|
|
96
|
+
addresses (the `::` forms too), email addresses, hostnames on network
|
|
97
|
+
top-level domains, or credential-shaped strings (provider API keys, AWS key
|
|
98
|
+
ids, GitHub and Slack tokens, private key headers, JWTs) in the body, in any
|
|
99
|
+
frontmatter value or on any raw frontmatter line. `trigger.hosts` is the one
|
|
100
|
+
field that holds a hostname, and it must be a public one (no `.internal`,
|
|
101
|
+
`.local`, `.lan`, `.corp` and the like). No URL in the body or in a
|
|
102
|
+
frontmatter field: nothing with `://`, no `www.`, no known scheme such as
|
|
103
|
+
`mailto:`, `tel:` or `data:` followed by anything, and no other `word:`
|
|
104
|
+
followed by a host or an address. A plain `word:word` (`batch:condition`,
|
|
105
|
+
`list:paired`) is prose. Paths include `$HOME/...`, `%USERPROFILE%\...` and
|
|
106
|
+
drive-less backslash paths. An IPv4 address starting with `0.` is not
|
|
107
|
+
refused, so a four-part tool version like `0.7.17.4` is not either; one
|
|
108
|
+
starting with any other number is.
|
|
109
|
+
- **Links** go only in `graduated_to`, `upstream` and `sources[].resource`, and
|
|
110
|
+
each must be a canonical `https` URL to one of the hosts in `LINK_HOSTS` at the
|
|
111
|
+
top of `validate.mjs`: no port, credentials, query, fragment, percent-escape
|
|
112
|
+
or `..`; a path of letters, digits and `._~/+-` only; and the path still gets
|
|
113
|
+
the identifying-data checks, hostnames and URLs included (so no commit SHAs,
|
|
114
|
+
uuids, home paths or a second host in the path). Those fields may hold free text
|
|
115
|
+
instead, like `galaxy-mcp#55`. To link somewhere new, add the host to
|
|
116
|
+
`LINK_HOSTS` in the same pull request and say why.
|
|
117
|
+
- **These are shape checks, not meaning checks.** A private hostname written as
|
|
118
|
+
prose, a person's name, a copied data value or an instruction aimed at the
|
|
119
|
+
model ("ignore prior instructions and...") all pass. They need the
|
|
120
|
+
contributor's own judgement and a reviewer's.
|
|
121
|
+
- **Dates** are `YYYY-MM-DD` strings that are also real calendar dates.
|
|
122
|
+
- **`generated.by`** matches `agent:<something>` or `human:<something>`;
|
|
123
|
+
**`verified[].by`** must be `human:<pseudonym>`. It is the one identity field
|
|
124
|
+
in the schema, and the shared tier uses maintainer pseudonyms rather than
|
|
125
|
+
contributor ids.
|
|
126
|
+
- **Signatures must be specific.** At least 8 characters, and never the
|
|
127
|
+
normalizer's `unknown` fallback, which would match every empty error.
|
|
128
|
+
- **Signatures must already be normalized.** The validator runs the same
|
|
129
|
+
normalization the matcher will run over a tool result and rejects any
|
|
130
|
+
signature it would change, naming the normalized form to store instead. A
|
|
131
|
+
signature stored raw can never match anything. Normalization takes the first
|
|
132
|
+
line, collapses whitespace, then replaces URLs with `<url>`, emails with
|
|
133
|
+
`<email>`, paths with two or more separators with `<path>`, runs of 16+ hex
|
|
134
|
+
characters with `<id>` and integers of 5+ digits with `<n>`, in that order,
|
|
135
|
+
and truncates to 200.
|
|
136
|
+
- **At least one trigger list must be non-empty.** A lesson nothing can match is
|
|
137
|
+
documentation, and documentation belongs in the GTN.
|
|
138
|
+
- **Per-entry shapes.** `mcp_tools` are `galaxy_*`; `hosts` are bare hostnames
|
|
139
|
+
with no scheme and no path; `extensions` start with a dot; `step_keywords` are
|
|
140
|
+
lowercase; `formats` are lowercase; `supersedes` entries are namespaced lesson
|
|
141
|
+
ids. Lists cap at 20 entries.
|
|
142
|
+
- **Caps.** title 120, description 200, each tag 40, cues 300, each signature
|
|
143
|
+
200, each tool id 200, each MCP tool name 80, each format 40, each host 100,
|
|
144
|
+
each extension 20, each step keyword 40, each `applies_to` field 200,
|
|
145
|
+
`evidence.method` 300, each source id 100, each free-text list entry 200, each
|
|
146
|
+
body section 600.
|
|
147
|
+
- **A `galaxy-api` lesson must have a non-empty `graduated_to`.** That namespace
|
|
148
|
+
exists for lessons whose durable fix lives elsewhere, and `graduated_to` is
|
|
149
|
+
what keeps them unsurfaced.
|
|
150
|
+
- **Directory shape.** A namespace directory holds `.md` lesson files only, one
|
|
151
|
+
level deep. Top-level files (this one, README, LICENSE, log, the scripts) are
|
|
152
|
+
not lessons and are not validated.
|
|
153
|
+
|
|
154
|
+
## The snapshot
|
|
155
|
+
|
|
156
|
+
`npm run build:lessons` writes `lessons/snapshot.json`:
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
interface LessonSnapshot {
|
|
160
|
+
schema: 1;
|
|
161
|
+
built_at: string; // ISO
|
|
162
|
+
source: { repo: "galaxyproject/orbit"; commit: string };
|
|
163
|
+
licence: "CC-BY-4.0";
|
|
164
|
+
lessons: Lesson[];
|
|
165
|
+
}
|
|
166
|
+
interface Lesson {
|
|
167
|
+
id: string; // "stats/na-coerced-to-zero-in-filters"
|
|
168
|
+
// every frontmatter field above, same names, same shapes
|
|
169
|
+
sections: {
|
|
170
|
+
symptom: string;
|
|
171
|
+
cause?: string;
|
|
172
|
+
check_first: string;
|
|
173
|
+
intervention: string;
|
|
174
|
+
validate: string;
|
|
175
|
+
not_when: string;
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
A lesson is left out when `status` is `deprecated` or when `stale_after` has
|
|
181
|
+
passed as of the snapshot's own `built_at`. `tags` in the snapshot is the
|
|
182
|
+
authored tags plus the lesson's `stage` values and `trigger.formats`, deduped.
|
|
183
|
+
|
|
184
|
+
Published file:
|
|
185
|
+
`https://raw.githubusercontent.com/galaxyproject/orbit/main/lessons/snapshot.json`.
|
|
186
|
+
A lesson's canonical page:
|
|
187
|
+
`https://github.com/galaxyproject/orbit/blob/main/lessons/<id>.md`.
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Build `lessons/snapshot.json`: the validated, committed JSON every consumer
|
|
4
|
+
* reads -- the package (the matcher), galaxy-mcp, and the hosted docs-search
|
|
5
|
+
* `lessons` collection.
|
|
6
|
+
*
|
|
7
|
+
* npm run build:lessons # validate, build, write snapshot.json
|
|
8
|
+
* npm run check:lessons # validate + fail if snapshot.json is out of date
|
|
9
|
+
*
|
|
10
|
+
* Same shape of gate as `sync:skills` / `check:skills`: the generated artifact
|
|
11
|
+
* is committed so consumers get it with no build step, and CI refuses a diff
|
|
12
|
+
* that changed `lessons/` without rebuilding.
|
|
13
|
+
*
|
|
14
|
+
* `built_at` and `source.commit` are provenance, not content, so `--check`
|
|
15
|
+
* reuses the committed values and the only thing it can fail on is a lesson
|
|
16
|
+
* that changed without a rebuild. Staleness is evaluated as of `built_at` for
|
|
17
|
+
* the same reason -- otherwise this gate would start failing on a date, on
|
|
18
|
+
* somebody else's unrelated pull request. Real-time staleness is a warning.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import fs from "node:fs";
|
|
22
|
+
import path from "node:path";
|
|
23
|
+
import { spawnSync } from "node:child_process";
|
|
24
|
+
import { realpathSync } from "node:fs";
|
|
25
|
+
import { fileURLToPath } from "node:url";
|
|
26
|
+
import { SECTIONS, collectLessonFiles, parseLesson, validateLessonsDir } from "./validate.mjs";
|
|
27
|
+
|
|
28
|
+
export const LESSONS_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
29
|
+
export const REPO_ROOT = path.resolve(LESSONS_DIR, "..");
|
|
30
|
+
export const SNAPSHOT_PATH = path.join(LESSONS_DIR, "snapshot.json");
|
|
31
|
+
|
|
32
|
+
export const SNAPSHOT_SCHEMA = 1;
|
|
33
|
+
export const SNAPSHOT_REPO = "galaxyproject/orbit";
|
|
34
|
+
export const SNAPSHOT_LICENCE = "CC-BY-4.0";
|
|
35
|
+
|
|
36
|
+
/** Past the end of its `stale_after` day, in UTC. */
|
|
37
|
+
export function isStale(staleAfter, nowMs) {
|
|
38
|
+
const end = Date.parse(`${staleAfter}T23:59:59Z`);
|
|
39
|
+
return Number.isFinite(end) && end < nowMs;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The exact shape `Date.prototype.toISOString` writes. Anything looser and a
|
|
44
|
+
* hand-edited `built_at` parses to NaN, which silently turns the staleness
|
|
45
|
+
* comparison off.
|
|
46
|
+
*/
|
|
47
|
+
export function isIsoTimestamp(value) {
|
|
48
|
+
if (typeof value !== "string") return false;
|
|
49
|
+
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value)) return false;
|
|
50
|
+
const ms = Date.parse(value);
|
|
51
|
+
return Number.isFinite(ms) && new Date(ms).toISOString() === value;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function dedupe(values) {
|
|
55
|
+
return [...new Set(values)];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* One snapshot entry. Every field is copied by name rather than spread, so the
|
|
60
|
+
* key order is deterministic (the drift gate compares bytes) and a frontmatter
|
|
61
|
+
* key the validator would have rejected cannot ride along into the published
|
|
62
|
+
* artifact.
|
|
63
|
+
*/
|
|
64
|
+
export function toSnapshotLesson(rel, frontmatter, sections) {
|
|
65
|
+
const fm = frontmatter;
|
|
66
|
+
const lesson = {
|
|
67
|
+
id: rel.replace(/\.md$/, ""),
|
|
68
|
+
type: fm.type,
|
|
69
|
+
title: fm.title,
|
|
70
|
+
description: fm.description,
|
|
71
|
+
// The build mirrors stage and formats into tags, so a consumer that only
|
|
72
|
+
// indexes tags (the docs-search collection does) still sees both axes.
|
|
73
|
+
tags: dedupe([...fm.tags, ...fm.stage, ...fm.trigger.formats]),
|
|
74
|
+
status: fm.status,
|
|
75
|
+
generated: { by: fm.generated.by, at: fm.generated.at },
|
|
76
|
+
};
|
|
77
|
+
if (fm.verified !== undefined) {
|
|
78
|
+
lesson.verified = fm.verified.map((v) => ({ by: v.by, at: v.at }));
|
|
79
|
+
}
|
|
80
|
+
lesson.stale_after = fm.stale_after;
|
|
81
|
+
lesson.sources = fm.sources.map((s) => {
|
|
82
|
+
const out = { id: s.id };
|
|
83
|
+
if (s.resource !== undefined) out.resource = s.resource;
|
|
84
|
+
if (s.title !== undefined) out.title = s.title;
|
|
85
|
+
return out;
|
|
86
|
+
});
|
|
87
|
+
lesson.kind = fm.kind;
|
|
88
|
+
lesson.stage = [...fm.stage];
|
|
89
|
+
lesson.trigger = {
|
|
90
|
+
signatures: [...fm.trigger.signatures],
|
|
91
|
+
tools: [...fm.trigger.tools],
|
|
92
|
+
mcp_tools: [...fm.trigger.mcp_tools],
|
|
93
|
+
formats: [...fm.trigger.formats],
|
|
94
|
+
hosts: [...fm.trigger.hosts],
|
|
95
|
+
extensions: [...fm.trigger.extensions],
|
|
96
|
+
step_keywords: [...fm.trigger.step_keywords],
|
|
97
|
+
};
|
|
98
|
+
lesson.cues = fm.cues;
|
|
99
|
+
lesson.applies_to = { versions: fm.applies_to.versions, tested: fm.applies_to.tested };
|
|
100
|
+
lesson.evidence = {
|
|
101
|
+
symptom: fm.evidence.symptom,
|
|
102
|
+
cause: fm.evidence.cause,
|
|
103
|
+
outcome: fm.evidence.outcome,
|
|
104
|
+
method: fm.evidence.method,
|
|
105
|
+
};
|
|
106
|
+
lesson.graduated_to = [...fm.graduated_to];
|
|
107
|
+
lesson.upstream = [...fm.upstream];
|
|
108
|
+
lesson.supersedes = [...fm.supersedes];
|
|
109
|
+
lesson.sections = {};
|
|
110
|
+
for (const spec of SECTIONS) {
|
|
111
|
+
if (sections[spec.key] !== undefined) lesson.sections[spec.key] = sections[spec.key];
|
|
112
|
+
}
|
|
113
|
+
return lesson;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Build the snapshot object. `nowMs` defaults to `builtAt` so a build and a
|
|
118
|
+
* later `--check` of the same bytes agree.
|
|
119
|
+
*/
|
|
120
|
+
export function buildSnapshot({ dir = LESSONS_DIR, builtAt, commit, nowMs } = {}) {
|
|
121
|
+
if (!isIsoTimestamp(builtAt)) {
|
|
122
|
+
throw new Error(`built_at must be an ISO timestamp (got ${JSON.stringify(builtAt)})`);
|
|
123
|
+
}
|
|
124
|
+
const asOf = nowMs ?? Date.parse(builtAt);
|
|
125
|
+
const lessons = [];
|
|
126
|
+
const skipped = [];
|
|
127
|
+
for (const rel of collectLessonFiles(dir)) {
|
|
128
|
+
const { frontmatter, sections } = parseLesson(fs.readFileSync(path.join(dir, rel), "utf8"));
|
|
129
|
+
const id = rel.replace(/\.md$/, "");
|
|
130
|
+
if (frontmatter.status === "deprecated") {
|
|
131
|
+
skipped.push({ id, why: "status: deprecated" });
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (isStale(frontmatter.stale_after, asOf)) {
|
|
135
|
+
skipped.push({ id, why: `past stale_after ${frontmatter.stale_after}` });
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
lessons.push(toSnapshotLesson(rel, frontmatter, sections));
|
|
139
|
+
}
|
|
140
|
+
const snapshot = {
|
|
141
|
+
schema: SNAPSHOT_SCHEMA,
|
|
142
|
+
built_at: builtAt,
|
|
143
|
+
source: { repo: SNAPSHOT_REPO, commit },
|
|
144
|
+
licence: SNAPSHOT_LICENCE,
|
|
145
|
+
lessons,
|
|
146
|
+
};
|
|
147
|
+
return { snapshot, skipped };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function serializeSnapshot(snapshot) {
|
|
151
|
+
return `${JSON.stringify(snapshot, null, 2)}\n`;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** First differing line of two serialized snapshots, as printable lines. */
|
|
155
|
+
export function firstDiff(committed, rebuilt) {
|
|
156
|
+
const a = committed.split("\n");
|
|
157
|
+
const b = rebuilt.split("\n");
|
|
158
|
+
const trunc = (s) =>
|
|
159
|
+
s === undefined ? "<end of file>" : s.length > 120 ? `${s.slice(0, 117)}...` : s;
|
|
160
|
+
for (let i = 0; i < Math.max(a.length, b.length); i++) {
|
|
161
|
+
if (a[i] === b[i]) continue;
|
|
162
|
+
return [
|
|
163
|
+
`first difference at line ${i + 1}:`,
|
|
164
|
+
`committed: ${trunc(a[i])}`,
|
|
165
|
+
`rebuilt: ${trunc(b[i])}`,
|
|
166
|
+
];
|
|
167
|
+
}
|
|
168
|
+
return ["the two serializations differ in length only"];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* The commit the corpus was read at. This is HEAD at build time, so it names
|
|
173
|
+
* the commit before the one that lands the snapshot -- which is the honest
|
|
174
|
+
* answer to "what was on disk when this was built".
|
|
175
|
+
*/
|
|
176
|
+
function headCommit(repoRoot) {
|
|
177
|
+
const run = spawnSync("git", ["rev-parse", "HEAD"], { cwd: repoRoot, encoding: "utf8" });
|
|
178
|
+
const sha = run.status === 0 ? run.stdout.trim() : "";
|
|
179
|
+
return /^[0-9a-f]{40}$/.test(sha) ? sha : "unknown";
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function reportViolations(label, violations) {
|
|
183
|
+
console.error(`${label} FAILED -- ${violations.length} schema violation(s)`);
|
|
184
|
+
for (const v of violations) console.error(` ${v}`);
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function build() {
|
|
189
|
+
const violations = validateLessonsDir(LESSONS_DIR);
|
|
190
|
+
if (violations.length > 0) reportViolations("build:lessons", violations);
|
|
191
|
+
|
|
192
|
+
const builtAt = process.env.LESSONS_BUILT_AT ?? new Date().toISOString();
|
|
193
|
+
const commit = process.env.LESSONS_COMMIT ?? headCommit(REPO_ROOT);
|
|
194
|
+
const { snapshot, skipped } = buildSnapshot({ builtAt, commit });
|
|
195
|
+
if (snapshot.lessons.length === 0) {
|
|
196
|
+
console.error("build:lessons FAILED -- every lesson was skipped, the snapshot would be empty");
|
|
197
|
+
for (const s of skipped) console.error(` ${s.id}: ${s.why}`);
|
|
198
|
+
process.exit(1);
|
|
199
|
+
}
|
|
200
|
+
fs.writeFileSync(SNAPSHOT_PATH, serializeSnapshot(snapshot));
|
|
201
|
+
console.log(`build:lessons OK -- ${snapshot.lessons.length} lesson(s) in lessons/snapshot.json`);
|
|
202
|
+
for (const s of skipped) console.log(` left out ${s.id} (${s.why})`);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* The drift gate as a function, so it can be exercised against any corpus.
|
|
207
|
+
* `failure` is the lines to print when it fails; `warnings` never fail it.
|
|
208
|
+
*/
|
|
209
|
+
export function checkSnapshot({
|
|
210
|
+
dir = LESSONS_DIR,
|
|
211
|
+
snapshotPath = SNAPSHOT_PATH,
|
|
212
|
+
nowMs = Date.now(),
|
|
213
|
+
} = {}) {
|
|
214
|
+
const violations = validateLessonsDir(dir);
|
|
215
|
+
if (violations.length > 0) {
|
|
216
|
+
return {
|
|
217
|
+
ok: false,
|
|
218
|
+
failure: [
|
|
219
|
+
`check:lessons FAILED -- ${violations.length} schema violation(s)`,
|
|
220
|
+
...violations.map((v) => ` ${v}`),
|
|
221
|
+
],
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
if (!fs.existsSync(snapshotPath)) {
|
|
225
|
+
return {
|
|
226
|
+
ok: false,
|
|
227
|
+
failure: [
|
|
228
|
+
"check:lessons FAILED -- lessons/snapshot.json is missing",
|
|
229
|
+
"\nRun `npm run build:lessons` and commit the result.",
|
|
230
|
+
],
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
const committedText = fs.readFileSync(snapshotPath, "utf8").replace(/\r\n/g, "\n");
|
|
234
|
+
let committed;
|
|
235
|
+
try {
|
|
236
|
+
committed = JSON.parse(committedText);
|
|
237
|
+
} catch (err) {
|
|
238
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
239
|
+
return {
|
|
240
|
+
ok: false,
|
|
241
|
+
failure: [`check:lessons FAILED -- lessons/snapshot.json is not valid JSON: ${message}`],
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
const builtAt = committed?.built_at;
|
|
245
|
+
if (!isIsoTimestamp(builtAt)) {
|
|
246
|
+
return {
|
|
247
|
+
ok: false,
|
|
248
|
+
failure: [
|
|
249
|
+
`check:lessons FAILED -- lessons/snapshot.json built_at is not an ISO timestamp (got ${JSON.stringify(builtAt)})`,
|
|
250
|
+
"\nRun `npm run build:lessons` and commit lessons/snapshot.json.",
|
|
251
|
+
],
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
const commit = typeof committed?.source?.commit === "string" ? committed.source.commit : "";
|
|
255
|
+
const { snapshot } = buildSnapshot({ dir, builtAt, commit });
|
|
256
|
+
const rebuilt = serializeSnapshot(snapshot);
|
|
257
|
+
if (rebuilt !== committedText) {
|
|
258
|
+
return {
|
|
259
|
+
ok: false,
|
|
260
|
+
failure: [
|
|
261
|
+
"check:lessons FAILED -- lessons/snapshot.json does not match lessons/",
|
|
262
|
+
...firstDiff(committedText, rebuilt).map((line) => ` ${line}`),
|
|
263
|
+
"\nRun `npm run build:lessons` and commit lessons/snapshot.json.",
|
|
264
|
+
],
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Not fatal: a lesson that has aged out should be re-verified or dropped
|
|
269
|
+
// deliberately, and a date is a bad reason to turn somebody else's CI red.
|
|
270
|
+
const warnings = snapshot.lessons
|
|
271
|
+
.filter((l) => isStale(l.stale_after, nowMs))
|
|
272
|
+
.map(
|
|
273
|
+
(l) =>
|
|
274
|
+
` warning: ${l.id} is past stale_after ${l.stale_after} -- re-verify it, or rebuild to drop it`,
|
|
275
|
+
);
|
|
276
|
+
return { ok: true, count: snapshot.lessons.length, warnings };
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function check() {
|
|
280
|
+
const result = checkSnapshot();
|
|
281
|
+
if (!result.ok) {
|
|
282
|
+
for (const line of result.failure) console.error(line);
|
|
283
|
+
process.exit(1);
|
|
284
|
+
}
|
|
285
|
+
for (const w of result.warnings) console.warn(w);
|
|
286
|
+
console.log(`check:lessons OK -- ${result.count} lesson(s) match lessons/snapshot.json`);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function isDirectInvocation() {
|
|
290
|
+
if (!process.argv[1]) return false;
|
|
291
|
+
try {
|
|
292
|
+
return fileURLToPath(import.meta.url) === realpathSync(process.argv[1]);
|
|
293
|
+
} catch {
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (isDirectInvocation()) {
|
|
299
|
+
const args = process.argv.slice(2);
|
|
300
|
+
if (args.length > 1 || (args.length === 1 && args[0] !== "--check")) {
|
|
301
|
+
console.error(`usage: build-snapshot.mjs [--check] (got ${args.join(" ")})`);
|
|
302
|
+
process.exit(2);
|
|
303
|
+
}
|
|
304
|
+
try {
|
|
305
|
+
if (args[0] === "--check") check();
|
|
306
|
+
else build();
|
|
307
|
+
} catch (err) {
|
|
308
|
+
console.error(`lessons/build-snapshot: ${err instanceof Error ? err.message : err}`);
|
|
309
|
+
process.exit(1);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Lesson
|
|
3
|
+
title: A supplementary-file download can return an HTML page saved under the expected filename
|
|
4
|
+
description: A landing page, consent interstitial or bot-block answers with 200 and the client saves it as the requested name, so the parse failure surfaces several steps later.
|
|
5
|
+
tags: [download, supplementary-data, file-type, landing-page]
|
|
6
|
+
status: draft
|
|
7
|
+
generated: { by: "human:loom-maintainers", at: "2026-09-30" }
|
|
8
|
+
stale_after: "2027-03-31"
|
|
9
|
+
sources:
|
|
10
|
+
- { id: "loom#356" }
|
|
11
|
+
- { id: "loom#282" }
|
|
12
|
+
|
|
13
|
+
kind: source-quirk
|
|
14
|
+
stage: [data-acquisition]
|
|
15
|
+
trigger:
|
|
16
|
+
signatures: []
|
|
17
|
+
tools: []
|
|
18
|
+
mcp_tools: []
|
|
19
|
+
formats: [xlsx, gz, tsv, csv]
|
|
20
|
+
hosts: ["doi.org", "zenodo.org", "figshare.com", "static-content.springer.com", "journals.plos.org", "www.ncbi.nlm.nih.gov"]
|
|
21
|
+
extensions: [".xlsx", ".tsv.gz", ".tsv", ".csv", ".gz"]
|
|
22
|
+
step_keywords: ["download", "supplementary", "fetch", "wget", "curl", "doi", "landing page"]
|
|
23
|
+
cues: "Fetching a supplementary or data file from a journal, a repository landing page, or a DOI link."
|
|
24
|
+
applies_to: { versions: "n/a", tested: "local download of journal supplementary files" }
|
|
25
|
+
evidence:
|
|
26
|
+
symptom: verified
|
|
27
|
+
cause: hypothesized
|
|
28
|
+
outcome: unvalidated
|
|
29
|
+
method: "the file was later found to be HTML or XML"
|
|
30
|
+
graduated_to: []
|
|
31
|
+
upstream: []
|
|
32
|
+
supersedes: []
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Symptom
|
|
36
|
+
|
|
37
|
+
An `.xlsx` or `.tsv.gz` will not parse, or parses into nonsense, several steps after it was
|
|
38
|
+
fetched.
|
|
39
|
+
|
|
40
|
+
## Cause
|
|
41
|
+
|
|
42
|
+
Likely: the URL was a landing page, a login or consent interstitial, or a bot-block response, and
|
|
43
|
+
the client saved the body under the requested name with a 200.
|
|
44
|
+
|
|
45
|
+
## Check first
|
|
46
|
+
|
|
47
|
+
Right after any download: file size, leading bytes (zip or gzip magic versus `<`), and
|
|
48
|
+
content-type if available.
|
|
49
|
+
|
|
50
|
+
## Intervention
|
|
51
|
+
|
|
52
|
+
Find the direct file URL, or have Galaxy fetch it server-side; if access is gated, tell the user
|
|
53
|
+
rather than working around it.
|
|
54
|
+
|
|
55
|
+
## Validate
|
|
56
|
+
|
|
57
|
+
The file opens as its claimed type and has the expected shape: sheets, columns, row count.
|
|
58
|
+
|
|
59
|
+
## Does NOT apply when
|
|
60
|
+
|
|
61
|
+
The file is genuinely the right type and the parse error is about its contents.
|