@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,706 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Background poller for active Galaxy workflow invocations.
|
|
3
|
+
*
|
|
4
|
+
* Part 2 of #67. Part 1 added the YAML counters + the Activity-tab UI
|
|
5
|
+
* section that draws progress bars from them. This file is the timer
|
|
6
|
+
* that keeps those counters fresh between agent turns: every
|
|
7
|
+
* POLL_INTERVAL_MS, scan the notebook for in-flight blocks; if any
|
|
8
|
+
* exist, run `checkInvocations` to advance status and write updated
|
|
9
|
+
* counters back to notebook.md.
|
|
10
|
+
*
|
|
11
|
+
* Lifecycle:
|
|
12
|
+
* - session_start → startGalaxyPoller(): unconditionally start the
|
|
13
|
+
* timer. Each tick is cheap when no blocks are in-flight (one
|
|
14
|
+
* notebook read + scan, no Galaxy call).
|
|
15
|
+
* - session_shutdown → stopGalaxyPoller(): clear timer.
|
|
16
|
+
* - Multiple session_start (brain restart) → start() stops any prior
|
|
17
|
+
* timer first; idempotent.
|
|
18
|
+
*
|
|
19
|
+
* Why "always running" instead of stopping on idle:
|
|
20
|
+
* If we stopped at "no in-flight blocks", the next time the agent
|
|
21
|
+
* recorded a new invocation mid-session we'd never wake up — only
|
|
22
|
+
* another session_start would. Avoids a circular import between
|
|
23
|
+
* tools.ts (which records invocations) and this file. The cost is
|
|
24
|
+
* one notebook read + scan per 15s, which is negligible.
|
|
25
|
+
*
|
|
26
|
+
* Concurrency: ticks are guarded by `inFlight` so a slow Galaxy GET
|
|
27
|
+
* doesn't stack ticks. The check itself uses the existing per-notebook
|
|
28
|
+
* lock in withNotebookLock, so a manual `galaxy_invocation_check_all`
|
|
29
|
+
* call from the agent doesn't race the poller.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import * as path from "path";
|
|
33
|
+
import { getNotebookPath } from "./state.js";
|
|
34
|
+
import {
|
|
35
|
+
findInvocationBlocks,
|
|
36
|
+
NotebookChangedError,
|
|
37
|
+
readNotebook,
|
|
38
|
+
statNotebook,
|
|
39
|
+
withNotebookLock,
|
|
40
|
+
writeNotebook,
|
|
41
|
+
} from "./notebook-writer.js";
|
|
42
|
+
import { checkInvocations, isInvocationLive } from "./tools.js";
|
|
43
|
+
import {
|
|
44
|
+
getGalaxyConfig,
|
|
45
|
+
galaxyGetInvocation,
|
|
46
|
+
galaxyGetJobDetails,
|
|
47
|
+
sameGalaxyServer,
|
|
48
|
+
} from "./galaxy-api.js";
|
|
49
|
+
import { buildResumePrompt, isResumableOutcome, type GalaxyFollowUp } from "./auto-resume.js";
|
|
50
|
+
import {
|
|
51
|
+
applyJobPollUpdate,
|
|
52
|
+
findJobBlocks,
|
|
53
|
+
isTerminalJobState,
|
|
54
|
+
jobStatusFromGalaxyState,
|
|
55
|
+
type JobYaml,
|
|
56
|
+
} from "./galaxy-job-block.js";
|
|
57
|
+
import { appendActivityEvent } from "./activity.js";
|
|
58
|
+
|
|
59
|
+
// 15s — ~4 polls/min × a few in-flight invocations stays well under
|
|
60
|
+
// usegalaxy.org's per-user rate budget while still feeling live. Background
|
|
61
|
+
// GETs never invoke the model, so this is independent of the model-facing
|
|
62
|
+
// status-read cooldown in galaxy-poll-guard.ts.
|
|
63
|
+
const POLL_INTERVAL_MS = 15_000;
|
|
64
|
+
|
|
65
|
+
let timer: ReturnType<typeof setInterval> | null = null;
|
|
66
|
+
/**
|
|
67
|
+
* The tick currently running, if any. Ticks don't stack -- a slow Galaxy GET
|
|
68
|
+
* would otherwise let the interval pile them up -- and holding the promise
|
|
69
|
+
* rather than a boolean lets a caller wait for the one already in flight.
|
|
70
|
+
*/
|
|
71
|
+
let inFlightTick: Promise<void> | null = null;
|
|
72
|
+
|
|
73
|
+
/** Surface a toast to the shell when a background invocation finishes. */
|
|
74
|
+
type PollerNotify = (text: string, level: "info" | "warning" | "error") => void;
|
|
75
|
+
let notify: PollerNotify | null = null;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Extra work to run on each tick, handed the notebook this tick already read.
|
|
79
|
+
*
|
|
80
|
+
* One hook rather than a second `setInterval`, because everything a second
|
|
81
|
+
* timer would need is already here: the cadence, the notebook read, and the
|
|
82
|
+
* knowledge of what is in flight. A second timer would also be a second thing
|
|
83
|
+
* to remember to stop. The live Galaxy panel registers through this.
|
|
84
|
+
*/
|
|
85
|
+
type PollTickHook = (content: string | null) => Promise<void>;
|
|
86
|
+
let tickHook: PollTickHook | null = null;
|
|
87
|
+
|
|
88
|
+
export function setPollTickHook(hook: PollTickHook | null): void {
|
|
89
|
+
tickHook = hook;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** For tests: whether anything is registered, and what. */
|
|
93
|
+
export function getPollTickHook(): PollTickHook | null {
|
|
94
|
+
return tickHook;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Capture's per-tick work: enrichment of finished runs, and a reconcile every
|
|
99
|
+
* few ticks (galaxy-reconcile.ts). Separate from `tickHook` because it has a
|
|
100
|
+
* different place in the tick -- it runs after this tick's transitions have
|
|
101
|
+
* landed, so a run that just finished is enriched on the same tick -- and
|
|
102
|
+
* because the live panel already owns that slot. Not awaited, for the same
|
|
103
|
+
* reason the panel hook isn't: a slow details fetch must not hold up polling.
|
|
104
|
+
*/
|
|
105
|
+
type CaptureTickHook = (tickNumber: number) => Promise<void>;
|
|
106
|
+
let captureHook: CaptureTickHook | null = null;
|
|
107
|
+
let tickCount = 0;
|
|
108
|
+
|
|
109
|
+
export function setCaptureTickHook(hook: CaptureTickHook | null): void {
|
|
110
|
+
captureHook = hook;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Hand a finished run back to the agent as a queued follow-up, so it verifies
|
|
115
|
+
* outputs itself instead of the toast asking the user to relay. Null when
|
|
116
|
+
* auto-resume is explicitly disabled.
|
|
117
|
+
*
|
|
118
|
+
* Must queue rather than interrupt: delivering a prompt to a brain that is
|
|
119
|
+
* mid-turn fails outright with "Agent is already processing".
|
|
120
|
+
*/
|
|
121
|
+
type PollerResume = (text: string) => void;
|
|
122
|
+
let resume: PollerResume | null = null;
|
|
123
|
+
|
|
124
|
+
function notifySafely(text: string, level: "info" | "warning" | "error"): void {
|
|
125
|
+
try {
|
|
126
|
+
notify?.(text, level);
|
|
127
|
+
} catch (err) {
|
|
128
|
+
// A stale shell must not prevent the agent from receiving its follow-up.
|
|
129
|
+
console.error("[galaxy-poller] notification failed:", err);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Subset of a checkInvocations result entry the poller needs for notifications. */
|
|
134
|
+
interface PollResultEntry {
|
|
135
|
+
invocationId: string;
|
|
136
|
+
notebookAnchor?: string;
|
|
137
|
+
label?: string;
|
|
138
|
+
priorStatus?: string;
|
|
139
|
+
jobSummary?: { ok?: number; running?: number; queued?: number; error?: number; other?: number };
|
|
140
|
+
activeJobs?: number;
|
|
141
|
+
newStatus?: string;
|
|
142
|
+
lastPolledAt?: string;
|
|
143
|
+
autoAction?: string;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Record a status change in the session's activity log.
|
|
148
|
+
*
|
|
149
|
+
* The poller calls checkInvocations directly rather than through the tool
|
|
150
|
+
* dispatcher, so every transition it made — the ones the user sees as a toast
|
|
151
|
+
* and a rewritten block — used to leave no row behind at all. This is the audit
|
|
152
|
+
* trail for work that advances between turns, with nobody watching.
|
|
153
|
+
*/
|
|
154
|
+
function logTransition(payload: Record<string, unknown>): void {
|
|
155
|
+
const nbPath = getNotebookPath();
|
|
156
|
+
if (!nbPath) return;
|
|
157
|
+
appendActivityEvent(path.dirname(nbPath), {
|
|
158
|
+
timestamp: new Date().toISOString(),
|
|
159
|
+
kind: "poll.transition",
|
|
160
|
+
source: "galaxy-poller",
|
|
161
|
+
payload,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Invocations we've already told the user about a mid-flight job failure for.
|
|
167
|
+
* That one is reported from a block that stays `in_progress` on purpose (the
|
|
168
|
+
* rest of the workflow is still under observation), so unlike a terminal
|
|
169
|
+
* transition it recurs on every tick until the run ends — announce it once.
|
|
170
|
+
* Reset per session in startGalaxyPoller.
|
|
171
|
+
*/
|
|
172
|
+
const announcedFailing = new Set<string>();
|
|
173
|
+
|
|
174
|
+
/** A block the poller has seen in flight in the notebook this session. */
|
|
175
|
+
interface TrackedBlock {
|
|
176
|
+
kind: "invocation" | "job";
|
|
177
|
+
id: string;
|
|
178
|
+
label: string;
|
|
179
|
+
/** Consecutive failed liveness checks after the block went missing. */
|
|
180
|
+
checkFailures?: number;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* How many times a missing block's liveness check may fail before we give up on
|
|
185
|
+
* it. A 403 or a 404 doesn't get better by asking again, and retrying forever
|
|
186
|
+
* would spend a Galaxy round trip per tick, per id, for the rest of the
|
|
187
|
+
* session.
|
|
188
|
+
*/
|
|
189
|
+
const MAX_MISSING_CHECK_ATTEMPTS = 3;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Every in-flight block we've seen this session, keyed `<kind>:<id>`. The
|
|
193
|
+
* notebook is the poller's only index of what to watch, so a block that leaves
|
|
194
|
+
* it -- an agent edit, a `bash` rewrite, a hand-pruned file -- takes a live
|
|
195
|
+
* Galaxy run out of Orbit's sight with nothing said. We can't put the block back
|
|
196
|
+
* (it is the user's file, and re-inserting it would fight whoever removed it),
|
|
197
|
+
* but we can refuse to let it go quietly. Reset per session in
|
|
198
|
+
* startGalaxyPoller.
|
|
199
|
+
*/
|
|
200
|
+
const trackedActive = new Map<string, TrackedBlock>();
|
|
201
|
+
|
|
202
|
+
function trackKey(kind: TrackedBlock["kind"], id: string): string {
|
|
203
|
+
return `${kind}:${id}`;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Remember the blocks that are in flight right now, and forget the ones that
|
|
208
|
+
* have reached a terminal status. What survives is exactly the set whose
|
|
209
|
+
* disappearance would cost us a running job.
|
|
210
|
+
*/
|
|
211
|
+
function trackActiveBlocks(content: string): void {
|
|
212
|
+
for (const inv of findInvocationBlocks(content)) {
|
|
213
|
+
const key = trackKey("invocation", inv.invocationId);
|
|
214
|
+
if (inv.status === "in_progress") {
|
|
215
|
+
trackedActive.set(key, {
|
|
216
|
+
kind: "invocation",
|
|
217
|
+
id: inv.invocationId,
|
|
218
|
+
label: inv.label || inv.notebookAnchor || inv.invocationId,
|
|
219
|
+
});
|
|
220
|
+
} else {
|
|
221
|
+
trackedActive.delete(key);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
for (const job of findJobBlocks(content)) {
|
|
225
|
+
const key = trackKey("job", job.jobId);
|
|
226
|
+
if (job.status === "in_progress") {
|
|
227
|
+
trackedActive.set(key, {
|
|
228
|
+
kind: "job",
|
|
229
|
+
id: job.jobId,
|
|
230
|
+
label: job.label || job.toolId || job.jobId,
|
|
231
|
+
});
|
|
232
|
+
} else {
|
|
233
|
+
trackedActive.delete(key);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** Ask Galaxy whether a run whose block has vanished is still going. */
|
|
239
|
+
async function isStillLive(block: TrackedBlock): Promise<{ live: boolean; state?: string }> {
|
|
240
|
+
if (block.kind === "invocation") {
|
|
241
|
+
const inv = await galaxyGetInvocation(block.id);
|
|
242
|
+
return { live: isInvocationLive(inv), state: inv.state };
|
|
243
|
+
}
|
|
244
|
+
const details = await galaxyGetJobDetails(block.id);
|
|
245
|
+
return { live: !isTerminalJobState(details.state), state: details.state };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** Say once, in the activity log and in the UI, that a live run left the notebook. */
|
|
249
|
+
function announceMissingBlock(block: TrackedBlock, state: string | undefined): void {
|
|
250
|
+
const nbPath = getNotebookPath();
|
|
251
|
+
if (nbPath) {
|
|
252
|
+
appendActivityEvent(path.dirname(nbPath), {
|
|
253
|
+
timestamp: new Date().toISOString(),
|
|
254
|
+
kind: "poll.block_missing",
|
|
255
|
+
source: "galaxy-poller",
|
|
256
|
+
payload: {
|
|
257
|
+
blockKind: block.kind,
|
|
258
|
+
id: block.id,
|
|
259
|
+
label: block.label,
|
|
260
|
+
galaxyState: state ?? null,
|
|
261
|
+
},
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
if (notify) {
|
|
265
|
+
notify(
|
|
266
|
+
`⚠️ Galaxy: "${block.label}" is still ${state ?? "running"} on Galaxy, but its ${block.kind} block is gone from the notebook — Orbit has stopped tracking it.`,
|
|
267
|
+
"warning",
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Compare what we're tracking against what the notebook still holds, and report
|
|
274
|
+
* anything that went missing while Galaxy says the run is alive. A block that
|
|
275
|
+
* disappeared after its run finished is unremarkable: it costs one GET and
|
|
276
|
+
* nothing else.
|
|
277
|
+
*/
|
|
278
|
+
async function reportMissingBlocks(content: string): Promise<void> {
|
|
279
|
+
if (trackedActive.size === 0) return;
|
|
280
|
+
const present = new Set<string>();
|
|
281
|
+
for (const inv of findInvocationBlocks(content)) {
|
|
282
|
+
present.add(trackKey("invocation", inv.invocationId));
|
|
283
|
+
}
|
|
284
|
+
for (const job of findJobBlocks(content)) present.add(trackKey("job", job.jobId));
|
|
285
|
+
|
|
286
|
+
const missing = [...trackedActive.entries()].filter(([key]) => !present.has(key));
|
|
287
|
+
if (missing.length === 0) return;
|
|
288
|
+
// No credentials, no verdict: keep the ids and ask again next tick.
|
|
289
|
+
if (!getGalaxyConfig()) return;
|
|
290
|
+
|
|
291
|
+
for (const [key, block] of missing) {
|
|
292
|
+
let result: { live: boolean; state?: string };
|
|
293
|
+
try {
|
|
294
|
+
result = await isStillLive(block);
|
|
295
|
+
} catch (err) {
|
|
296
|
+
// Galaxy briefly unreachable. Stay tracked and ask again next tick; one
|
|
297
|
+
// unreachable id must not cost the others their check. A few attempts in,
|
|
298
|
+
// stop asking -- the answer isn't coming.
|
|
299
|
+
console.error(`[galaxy-poller] ${block.kind} ${block.id} liveness check failed:`, err);
|
|
300
|
+
const failures = (block.checkFailures ?? 0) + 1;
|
|
301
|
+
if (failures >= MAX_MISSING_CHECK_ATTEMPTS) trackedActive.delete(key);
|
|
302
|
+
else trackedActive.set(key, { ...block, checkFailures: failures });
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
// One verdict per id, either way: the block is gone, so there is nothing
|
|
306
|
+
// left to re-examine. Recording it again re-arms the tracking.
|
|
307
|
+
trackedActive.delete(key);
|
|
308
|
+
if (result.live) announceMissingBlock(block, result.state);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/** How many times a job update re-reads and retries before giving up the tick. */
|
|
313
|
+
const MAX_JOB_PERSIST_ATTEMPTS = 3;
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Persist one job's poll result, returning whether it actually landed.
|
|
317
|
+
*
|
|
318
|
+
* Same discipline as persistInvocationUpdates: stamp *before* the read (a stamp
|
|
319
|
+
* taken after would let a write that landed in between look unchanged), apply
|
|
320
|
+
* only poll-owned fields so a concurrent label edit survives, and hand the stamp
|
|
321
|
+
* to writeNotebook so an out-of-band edit fails the compare-and-swap instead of
|
|
322
|
+
* being silently overwritten (#391). The lock alone can't do this -- it only
|
|
323
|
+
* orders Orbit's own writers, and the agent edits notebook.md directly.
|
|
324
|
+
*/
|
|
325
|
+
async function persistJobUpdate(
|
|
326
|
+
nbPath: string,
|
|
327
|
+
update: Parameters<typeof applyJobPollUpdate>[1],
|
|
328
|
+
): Promise<{ written: boolean; priorStatus?: JobYaml["status"] }> {
|
|
329
|
+
let lastError: unknown;
|
|
330
|
+
for (let attempt = 0; attempt < MAX_JOB_PERSIST_ATTEMPTS; attempt++) {
|
|
331
|
+
const stamp = await statNotebook(nbPath);
|
|
332
|
+
// Read regardless of the stat so a genuinely missing notebook surfaces its
|
|
333
|
+
// own ENOENT rather than being dressed up as a lost race.
|
|
334
|
+
const fresh = await readNotebook(nbPath);
|
|
335
|
+
if (!stamp) {
|
|
336
|
+
lastError = new NotebookChangedError(nbPath);
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
// The status as it is now, not as the tick's opening snapshot had it: the
|
|
340
|
+
// write below refreshes last_polled_at either way, so "we wrote" is not the
|
|
341
|
+
// same question as "we changed the outcome".
|
|
342
|
+
const priorStatus = findJobBlocks(fresh).find((j) => j.jobId === update.jobId)?.status;
|
|
343
|
+
const updated = applyJobPollUpdate(fresh, update);
|
|
344
|
+
// Block gone, or already carrying this result: nothing to write, nothing
|
|
345
|
+
// to announce.
|
|
346
|
+
if (updated === fresh) return { written: false };
|
|
347
|
+
try {
|
|
348
|
+
await writeNotebook(nbPath, updated, stamp);
|
|
349
|
+
return { written: true, priorStatus };
|
|
350
|
+
} catch (error) {
|
|
351
|
+
if (!(error instanceof NotebookChangedError)) throw error;
|
|
352
|
+
lastError = error;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
throw lastError;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/** The toast for a job that stopped running, matched to why it stopped. */
|
|
359
|
+
function jobFinishedToast(
|
|
360
|
+
status: ReturnType<typeof jobStatusFromGalaxyState>,
|
|
361
|
+
label: string,
|
|
362
|
+
state: string | undefined,
|
|
363
|
+
willResume = false,
|
|
364
|
+
): [string, "info" | "warning" | "error"] {
|
|
365
|
+
switch (status) {
|
|
366
|
+
case "completed":
|
|
367
|
+
return [
|
|
368
|
+
`✅ Galaxy: "${label}" finished${willResume ? " — outputs require verification." : " — automatic follow-up disabled."}`,
|
|
369
|
+
"info",
|
|
370
|
+
];
|
|
371
|
+
case "cancelled":
|
|
372
|
+
return [`⏹️ Galaxy: "${label}" was cancelled (${state}) — it produced no outputs.`, "info"];
|
|
373
|
+
case "skipped":
|
|
374
|
+
return [`⏭️ Galaxy: "${label}" was skipped — its step's condition wasn't met.`, "info"];
|
|
375
|
+
default:
|
|
376
|
+
return [
|
|
377
|
+
`❌ Galaxy: "${label}" failed (${state})${willResume ? " — failure recorded." : " — automatic follow-up disabled."}`,
|
|
378
|
+
"warning",
|
|
379
|
+
];
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/** The notebook as it is right now, or null if there isn't one to read. */
|
|
384
|
+
async function readNotebookOrNull(): Promise<string | null> {
|
|
385
|
+
const nbPath = getNotebookPath();
|
|
386
|
+
if (!nbPath) return null;
|
|
387
|
+
try {
|
|
388
|
+
return await readNotebook(nbPath);
|
|
389
|
+
} catch {
|
|
390
|
+
// Notebook missing or unreadable — nothing to advance this tick.
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function hasInProgressInvocations(content: string): boolean {
|
|
396
|
+
return findInvocationBlocks(content).some((b) => b.status === "in_progress");
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Advance in-flight `loom-job` blocks -- single Galaxy tool runs, which have no
|
|
401
|
+
* invocation to poll. One GET per in-flight job, and only for jobs that are
|
|
402
|
+
* still running, so an idle notebook costs nothing beyond the scan the
|
|
403
|
+
* invocation path already does.
|
|
404
|
+
*/
|
|
405
|
+
async function tickJobs(content: string, followUps: GalaxyFollowUp[]): Promise<void> {
|
|
406
|
+
const nbPath = getNotebookPath();
|
|
407
|
+
if (!nbPath) return;
|
|
408
|
+
|
|
409
|
+
const pending = findJobBlocks(content).filter((j) => j.status === "in_progress");
|
|
410
|
+
if (pending.length === 0) return;
|
|
411
|
+
const currentServer = getGalaxyConfig()?.url;
|
|
412
|
+
if (!currentServer) return;
|
|
413
|
+
|
|
414
|
+
for (const job of pending) {
|
|
415
|
+
let state: string | undefined;
|
|
416
|
+
try {
|
|
417
|
+
state = (await galaxyGetJobDetails(job.jobId)).state;
|
|
418
|
+
} catch (err) {
|
|
419
|
+
// One unreachable job must not stop the others, or kill the timer.
|
|
420
|
+
console.error(`[galaxy-poller] job ${job.jobId} poll failed:`, err);
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
if (!isTerminalJobState(state)) {
|
|
424
|
+
// Still running, so there's no transition to record -- but the GET just
|
|
425
|
+
// answered, which is the proof a block the record tool could only write
|
|
426
|
+
// `server_verified: false` is waiting for. Without this the flag would
|
|
427
|
+
// sit false for the whole run and only clear when the job ends.
|
|
428
|
+
if (job.serverVerified === false && sameGalaxyServer(job.galaxyServerUrl, currentServer)) {
|
|
429
|
+
try {
|
|
430
|
+
await withNotebookLock(nbPath, () =>
|
|
431
|
+
// Only the flag and the timestamp: this write knows nothing about
|
|
432
|
+
// the outcome, and the snapshot's status is already older than
|
|
433
|
+
// whatever the fresh read inside persistJobUpdate will see.
|
|
434
|
+
persistJobUpdate(nbPath, {
|
|
435
|
+
jobId: job.jobId,
|
|
436
|
+
lastPolledAt: new Date().toISOString(),
|
|
437
|
+
serverVerified: true,
|
|
438
|
+
}),
|
|
439
|
+
);
|
|
440
|
+
} catch (err) {
|
|
441
|
+
// Nothing was announced, so a lost write costs only a retry next tick.
|
|
442
|
+
console.error(`[galaxy-poller] job ${job.jobId} verification update failed:`, err);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const status = jobStatusFromGalaxyState(state);
|
|
449
|
+
const polledAt = new Date().toISOString();
|
|
450
|
+
let persisted: { written: boolean; priorStatus?: JobYaml["status"] };
|
|
451
|
+
try {
|
|
452
|
+
persisted = await withNotebookLock(nbPath, () =>
|
|
453
|
+
persistJobUpdate(nbPath, {
|
|
454
|
+
jobId: job.jobId,
|
|
455
|
+
status,
|
|
456
|
+
galaxyState: state,
|
|
457
|
+
lastPolledAt: polledAt,
|
|
458
|
+
// Only the server the block names can confirm the block's id.
|
|
459
|
+
serverVerified: sameGalaxyServer(job.galaxyServerUrl, currentServer),
|
|
460
|
+
}),
|
|
461
|
+
);
|
|
462
|
+
} catch (err) {
|
|
463
|
+
// Lost the write. Say nothing and let the next tick re-poll: the block is
|
|
464
|
+
// still in_progress on disk, so announcing a transition we failed to
|
|
465
|
+
// record would leave the notebook and the user telling different stories.
|
|
466
|
+
console.error(`[galaxy-poller] job ${job.jobId} update failed:`, err);
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
// The block was deleted mid-poll, or another writer already advanced it.
|
|
470
|
+
// Either way this tick didn't transition anything, so there's no news.
|
|
471
|
+
if (!persisted.written) continue;
|
|
472
|
+
if (persisted.priorStatus === status) continue;
|
|
473
|
+
|
|
474
|
+
const label = job.label || job.toolId || job.jobId;
|
|
475
|
+
logTransition({
|
|
476
|
+
blockKind: "job",
|
|
477
|
+
id: job.jobId,
|
|
478
|
+
label,
|
|
479
|
+
toolId: job.toolId ?? null,
|
|
480
|
+
from: persisted.priorStatus ?? job.status,
|
|
481
|
+
to: status,
|
|
482
|
+
galaxyState: state ?? null,
|
|
483
|
+
lastPolledAt: polledAt,
|
|
484
|
+
});
|
|
485
|
+
const willResume = resume !== null && isResumableOutcome(status);
|
|
486
|
+
notifySafely(...jobFinishedToast(status, label, state, willResume));
|
|
487
|
+
if (isResumableOutcome(status)) {
|
|
488
|
+
followUps.push({
|
|
489
|
+
kind: "job",
|
|
490
|
+
id: job.jobId,
|
|
491
|
+
label,
|
|
492
|
+
notebookAnchor: job.notebookAnchor,
|
|
493
|
+
outcome: status,
|
|
494
|
+
detail: state,
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/** Run a poll tick now, or hand back the one already running. */
|
|
501
|
+
function tick(): Promise<void> {
|
|
502
|
+
if (inFlightTick) return inFlightTick;
|
|
503
|
+
inFlightTick = runTick().finally(() => {
|
|
504
|
+
inFlightTick = null;
|
|
505
|
+
});
|
|
506
|
+
return inFlightTick;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Poll once and wait for it. Exported so a caller that wants fresh counters
|
|
511
|
+
* right now doesn't have to sit out the interval.
|
|
512
|
+
*/
|
|
513
|
+
export function pollGalaxyNow(): Promise<void> {
|
|
514
|
+
return tick();
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
async function runTick(): Promise<void> {
|
|
518
|
+
const tickNotebook = getNotebookPath();
|
|
519
|
+
const followUps: GalaxyFollowUp[] = [];
|
|
520
|
+
try {
|
|
521
|
+
// One read per tick, shared by everything below: what the notebook says is
|
|
522
|
+
// in flight is the whole of the poller's worklist.
|
|
523
|
+
const content = await readNotebookOrNull();
|
|
524
|
+
// Before the early returns below: a hook that only ran when the notebook
|
|
525
|
+
// had in-flight blocks would be a hook that stops the moment the analysis
|
|
526
|
+
// goes quiet, which is exactly when a panel still has to say something.
|
|
527
|
+
//
|
|
528
|
+
// Deliberately not awaited. A hook is an extra, and this tick's real work
|
|
529
|
+
// -- advancing in-flight invocations and jobs -- must not wait behind one
|
|
530
|
+
// that is talking to a Galaxy that has stopped answering. The hook is
|
|
531
|
+
// responsible for its own re-entrancy; both failure paths are swallowed
|
|
532
|
+
// here so a rejection cannot surface as an unhandled one.
|
|
533
|
+
if (tickHook) {
|
|
534
|
+
try {
|
|
535
|
+
void tickHook(content).catch((err) => {
|
|
536
|
+
console.error("[galaxy-poller] tick hook failed:", err);
|
|
537
|
+
});
|
|
538
|
+
} catch (err) {
|
|
539
|
+
console.error("[galaxy-poller] tick hook threw:", err);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
if (content === null) {
|
|
543
|
+
// The notebook itself is gone, so every block we were watching went with
|
|
544
|
+
// it -- same silencing, one level up. An unreadable-but-present notebook
|
|
545
|
+
// is a transient we say nothing about; an absent one is not.
|
|
546
|
+
const nbPath = getNotebookPath();
|
|
547
|
+
if (nbPath && !(await statNotebook(nbPath))) await reportMissingBlocks("");
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
trackActiveBlocks(content);
|
|
551
|
+
await reportMissingBlocks(content);
|
|
552
|
+
|
|
553
|
+
// Tool runs are tracked separately from workflow invocations and are the
|
|
554
|
+
// only thing advancing in a session that never invoked a workflow (#413).
|
|
555
|
+
await tickJobs(content, followUps);
|
|
556
|
+
|
|
557
|
+
// Cheap path when nothing's in-flight: scan and return.
|
|
558
|
+
if (!hasInProgressInvocations(content)) return;
|
|
559
|
+
if (!getGalaxyConfig()) {
|
|
560
|
+
// Credentials disappeared (user disconnected mid-session). Skip
|
|
561
|
+
// this tick; if creds come back the next tick picks up.
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
const result = await checkInvocations(undefined);
|
|
565
|
+
// Fire a completion toast for any invocation that JUST reached a terminal
|
|
566
|
+
// state this tick. The poller only checks blocks that were in_progress, so
|
|
567
|
+
// an autoAction of completed/failed is a fresh transition that won't recur
|
|
568
|
+
// (the block is terminal next tick and no longer checked) — notify once.
|
|
569
|
+
const results = (result.details as { results?: PollResultEntry[] } | undefined)?.results;
|
|
570
|
+
// Not gated on `notify`: a headless shell has no toast to show but must
|
|
571
|
+
// still hand the finished run back to the agent when auto-resume is on.
|
|
572
|
+
if (Array.isArray(results)) {
|
|
573
|
+
const willResume = resume !== null;
|
|
574
|
+
for (const r of results) {
|
|
575
|
+
const label = r.label || r.notebookAnchor || r.invocationId;
|
|
576
|
+
// A row for what the block's status actually became, and only when it
|
|
577
|
+
// became something else: `autoAction` survives the check's own blanking
|
|
578
|
+
// only for a transition that landed on disk, and a mid-flight failure
|
|
579
|
+
// deliberately leaves the status where it was.
|
|
580
|
+
if (r.autoAction && r.newStatus && r.newStatus !== r.priorStatus) {
|
|
581
|
+
logTransition({
|
|
582
|
+
blockKind: "invocation",
|
|
583
|
+
id: r.invocationId,
|
|
584
|
+
label,
|
|
585
|
+
notebookAnchor: r.notebookAnchor ?? null,
|
|
586
|
+
from: r.priorStatus ?? "in_progress",
|
|
587
|
+
to: r.newStatus,
|
|
588
|
+
outcome: r.autoAction,
|
|
589
|
+
counters: { ...(r.jobSummary ?? {}), active: r.activeJobs ?? 0 },
|
|
590
|
+
lastPolledAt: r.lastPolledAt ?? null,
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
if (r.autoAction === "completed") {
|
|
594
|
+
notifySafely(
|
|
595
|
+
`✅ Galaxy: "${label}" finished (${r.jobSummary?.ok ?? 0} jobs ok)${willResume ? " — outputs require verification." : " — automatic follow-up disabled."}`,
|
|
596
|
+
"info",
|
|
597
|
+
);
|
|
598
|
+
followUps.push({
|
|
599
|
+
kind: "invocation",
|
|
600
|
+
id: r.invocationId,
|
|
601
|
+
label,
|
|
602
|
+
notebookAnchor: r.notebookAnchor,
|
|
603
|
+
outcome: "completed",
|
|
604
|
+
});
|
|
605
|
+
} else if (r.autoAction === "failed") {
|
|
606
|
+
notifySafely(
|
|
607
|
+
`❌ Galaxy: "${label}" failed (${r.jobSummary?.error ?? 0} job error(s))${willResume ? " — failure recorded." : " — automatic follow-up disabled."}`,
|
|
608
|
+
"warning",
|
|
609
|
+
);
|
|
610
|
+
followUps.push({
|
|
611
|
+
kind: "invocation",
|
|
612
|
+
id: r.invocationId,
|
|
613
|
+
label,
|
|
614
|
+
notebookAnchor: r.notebookAnchor,
|
|
615
|
+
outcome: "failed",
|
|
616
|
+
detail: `${r.jobSummary?.error ?? 0} job error(s)`,
|
|
617
|
+
});
|
|
618
|
+
} else if (r.autoAction === "cancelled") {
|
|
619
|
+
notifySafely(
|
|
620
|
+
`⏹️ Galaxy: "${label}" was cancelled — ${r.jobSummary?.ok ?? 0} job(s) finished before it stopped.`,
|
|
621
|
+
"info",
|
|
622
|
+
);
|
|
623
|
+
} else if (r.autoAction === "failing" && !announcedFailing.has(r.invocationId)) {
|
|
624
|
+
announcedFailing.add(r.invocationId);
|
|
625
|
+
notifySafely(
|
|
626
|
+
`⚠️ Galaxy: "${label}" — ${r.jobSummary?.error ?? 0} job(s) failed, ${r.activeJobs ?? 0} still running${willResume ? " — failure recorded." : " — automatic follow-up disabled."}`,
|
|
627
|
+
"warning",
|
|
628
|
+
);
|
|
629
|
+
followUps.push({
|
|
630
|
+
kind: "invocation",
|
|
631
|
+
id: r.invocationId,
|
|
632
|
+
label,
|
|
633
|
+
notebookAnchor: r.notebookAnchor,
|
|
634
|
+
outcome: "failing",
|
|
635
|
+
detail: `${r.jobSummary?.error ?? 0} job(s) failed, ${r.activeJobs ?? 0} still running`,
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
} catch (err) {
|
|
641
|
+
// Don't kill the timer on a single bad poll — Galaxy may be
|
|
642
|
+
// briefly unreachable. Log and try again on the next tick.
|
|
643
|
+
console.error("[galaxy-poller] tick failed:", err);
|
|
644
|
+
} finally {
|
|
645
|
+
// Batch jobs and workflows into one turn, even if a later poll request
|
|
646
|
+
// failed. Queuing each finished import separately floods the agent.
|
|
647
|
+
// Deliver through whoever owns the poller now, not whoever started this
|
|
648
|
+
// tick: the transitions are already persisted, so a replacement session
|
|
649
|
+
// on the same notebook would never see them in_progress again. A stopped
|
|
650
|
+
// poller has no resume, and a different notebook's session isn't ours.
|
|
651
|
+
const deliver = resume;
|
|
652
|
+
if (deliver && followUps.length > 0 && getNotebookPath() === tickNotebook) {
|
|
653
|
+
try {
|
|
654
|
+
deliver(buildResumePrompt(followUps));
|
|
655
|
+
} catch (err) {
|
|
656
|
+
console.error("[galaxy-poller] auto-resume send failed:", err);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
tickCount++;
|
|
660
|
+
if (captureHook) {
|
|
661
|
+
try {
|
|
662
|
+
void captureHook(tickCount).catch((err) => {
|
|
663
|
+
console.error("[galaxy-poller] capture hook failed:", err);
|
|
664
|
+
});
|
|
665
|
+
} catch (err) {
|
|
666
|
+
console.error("[galaxy-poller] capture hook threw:", err);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
export function startGalaxyPoller(notifyFn?: PollerNotify, resumeFn?: PollerResume): void {
|
|
673
|
+
stopGalaxyPoller();
|
|
674
|
+
// Capture the shell notifier (from the session_start ctx) so a completed
|
|
675
|
+
// background invocation can toast the user. Refreshed each session_start.
|
|
676
|
+
notify = notifyFn ?? null;
|
|
677
|
+
// Null when auto-resume is disabled; the caller decides, so the poller
|
|
678
|
+
// stays free of config lookups on a 15s timer.
|
|
679
|
+
resume = resumeFn ?? null;
|
|
680
|
+
announcedFailing.clear();
|
|
681
|
+
trackedActive.clear();
|
|
682
|
+
// Idempotent: a brain restart triggers a new session_start without
|
|
683
|
+
// session_shutdown firing first in some failure modes. Stop any
|
|
684
|
+
// pre-existing timer so we don't double-poll.
|
|
685
|
+
// Fire one immediate tick so a session resumed with in-flight blocks
|
|
686
|
+
// gets fresh counters within the first second instead of waiting 15s.
|
|
687
|
+
void tick();
|
|
688
|
+
const interval = setInterval(tick, POLL_INTERVAL_MS);
|
|
689
|
+
// A background refresher must never be the reason the process stays alive.
|
|
690
|
+
// In print/rpc modes (`--mode json`, evals) the work finishes and nothing
|
|
691
|
+
// else holds the loop, so an armed interval kept the process up until
|
|
692
|
+
// something killed it; session_shutdown clears the timer, but relying on
|
|
693
|
+
// shutdown running is what made that a 15s-per-run tax when it didn't.
|
|
694
|
+
// Interactive and Orbit sessions are held open by stdin, so unref costs
|
|
695
|
+
// them nothing.
|
|
696
|
+
interval.unref?.();
|
|
697
|
+
timer = interval;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
export function stopGalaxyPoller(): void {
|
|
701
|
+
resume = null;
|
|
702
|
+
if (timer) {
|
|
703
|
+
clearInterval(timer);
|
|
704
|
+
timer = null;
|
|
705
|
+
}
|
|
706
|
+
}
|