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