@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,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ProvenanceFs over the real file system: today's bytes for the Node
|
|
3
|
+
* shells, moved here from galaxy-provenance.ts so that module imports no fs.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as fs from "fs";
|
|
7
|
+
import * as fsp from "fs/promises";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
import { randomHex } from "../../shared/random.js";
|
|
10
|
+
import type { ProvenanceFs, ProvenanceStat } from "./provenance-fs";
|
|
11
|
+
|
|
12
|
+
const code = (err: unknown) => (err as NodeJS.ErrnoException)?.code;
|
|
13
|
+
|
|
14
|
+
export const fileProvenanceFs: ProvenanceFs = {
|
|
15
|
+
async lstat(p): Promise<ProvenanceStat | null> {
|
|
16
|
+
try {
|
|
17
|
+
return await fsp.lstat(p);
|
|
18
|
+
} catch (err) {
|
|
19
|
+
if (code(err) === "ENOENT") return null;
|
|
20
|
+
throw err;
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
lstatSync(p): ProvenanceStat | null {
|
|
24
|
+
try {
|
|
25
|
+
return fs.lstatSync(p);
|
|
26
|
+
} catch (err) {
|
|
27
|
+
if (code(err) === "ENOENT") return null;
|
|
28
|
+
throw err;
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
async mkdir(p) {
|
|
32
|
+
try {
|
|
33
|
+
await fsp.mkdir(p);
|
|
34
|
+
} catch (err) {
|
|
35
|
+
if (code(err) !== "EEXIST") throw err;
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
readFile: (p) => fsp.readFile(p, "utf-8"),
|
|
39
|
+
readFileSync: (p) => fs.readFileSync(p, "utf-8"),
|
|
40
|
+
// `wx`: a planted file or symlink at the path fails the open instead of
|
|
41
|
+
// being written through.
|
|
42
|
+
writeExclusive: (p, text) => fsp.writeFile(p, text, { encoding: "utf-8", flag: "wx" }),
|
|
43
|
+
async replace(file, text) {
|
|
44
|
+
const temp = path.join(
|
|
45
|
+
path.dirname(file),
|
|
46
|
+
`.${path.basename(file)}.${process.pid}.${randomHex(6)}.tmp`,
|
|
47
|
+
);
|
|
48
|
+
await fsp.writeFile(temp, text, { encoding: "utf-8", flag: "wx" });
|
|
49
|
+
try {
|
|
50
|
+
// rename() replaces a symlink at the target rather than following it, and
|
|
51
|
+
// readers see the old record or the new one, never half of either.
|
|
52
|
+
await fsp.rename(temp, file);
|
|
53
|
+
} catch (err) {
|
|
54
|
+
await fsp.rm(temp, { force: true });
|
|
55
|
+
throw err;
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
readdir: (dir) => fsp.readdir(dir),
|
|
59
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The byte layer under galaxy-provenance.ts: exactly the file operations the
|
|
3
|
+
* provenance records and the reconcile cursor make, so a shell with no
|
|
4
|
+
* directory beside its notebook can keep them somewhere else. The ownership,
|
|
5
|
+
* symlink and validation logic stays in galaxy-provenance.ts; a backend only
|
|
6
|
+
* stores bytes.
|
|
7
|
+
*
|
|
8
|
+
* Types only, no Node imports: the browser's conformance test counts Node
|
|
9
|
+
* edges, and this file sits in every backend's import graph.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export interface ProvenanceStat {
|
|
13
|
+
isFile(): boolean;
|
|
14
|
+
isDirectory(): boolean;
|
|
15
|
+
isSymbolicLink(): boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ProvenanceFs {
|
|
19
|
+
/** Of the entry itself (a symlink reports as one); null when absent. */
|
|
20
|
+
lstat(p: string): Promise<ProvenanceStat | null>;
|
|
21
|
+
lstatSync(p: string): ProvenanceStat | null;
|
|
22
|
+
/** One level; an existing directory is not an error. */
|
|
23
|
+
mkdir(p: string): Promise<void>;
|
|
24
|
+
readFile(p: string): Promise<string>;
|
|
25
|
+
readFileSync(p: string): string;
|
|
26
|
+
/** Create, never overwrite: rejects with { code: "EEXIST" } when p exists, a planted symlink included. */
|
|
27
|
+
writeExclusive(p: string, text: string): Promise<void>;
|
|
28
|
+
/** Create or replace so a reader sees the old text or the new, never half of either. */
|
|
29
|
+
replace(p: string, text: string): Promise<void>;
|
|
30
|
+
/** Entry names directly under dir. */
|
|
31
|
+
readdir(dir: string): Promise<string[]>;
|
|
32
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A ProvenanceFs over a Map, for a shell with no directory beside its
|
|
3
|
+
* notebook: the browser worker keeps attempt records and the reconcile cursor
|
|
4
|
+
* for the life of the process. The paths carry the analysis dir, so two
|
|
5
|
+
* records hosted by one worker keep separate provenance on the one Map.
|
|
6
|
+
*
|
|
7
|
+
* No Node imports here: the browser's conformance test counts Node edges.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { ProvenanceFs, ProvenanceStat } from "./provenance-fs";
|
|
11
|
+
|
|
12
|
+
const stat = (kind: "file" | "dir"): ProvenanceStat => ({
|
|
13
|
+
isFile: () => kind === "file",
|
|
14
|
+
isDirectory: () => kind === "dir",
|
|
15
|
+
isSymbolicLink: () => false,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Exactly one separator and one name past the directory.
|
|
19
|
+
const CHILD = /^[\\/][^\\/]+$/;
|
|
20
|
+
|
|
21
|
+
export function memoryProvenanceFs(
|
|
22
|
+
files = new Map<string, string>(),
|
|
23
|
+
): ProvenanceFs & { files: Map<string, string> } {
|
|
24
|
+
const dirs = new Set<string>();
|
|
25
|
+
// galaxy-provenance.ts reads `err.code` the way it reads Node's, so the codes match.
|
|
26
|
+
const errno = (code: string, p: string) => Object.assign(new Error(`${code}: ${p}`), { code });
|
|
27
|
+
const lstatSync = (p: string) => (files.has(p) ? stat("file") : dirs.has(p) ? stat("dir") : null);
|
|
28
|
+
const readFileSync = (p: string) => {
|
|
29
|
+
const text = files.get(p);
|
|
30
|
+
if (text === undefined) throw errno("ENOENT", p);
|
|
31
|
+
return text;
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
files,
|
|
35
|
+
lstat: async (p) => lstatSync(p),
|
|
36
|
+
lstatSync,
|
|
37
|
+
mkdir: async (p) => {
|
|
38
|
+
dirs.add(p);
|
|
39
|
+
},
|
|
40
|
+
readFile: async (p) => readFileSync(p),
|
|
41
|
+
readFileSync,
|
|
42
|
+
writeExclusive: async (p, text) => {
|
|
43
|
+
if (files.has(p)) throw errno("EEXIST", p);
|
|
44
|
+
files.set(p, text);
|
|
45
|
+
},
|
|
46
|
+
replace: async (p, text) => {
|
|
47
|
+
files.set(p, text);
|
|
48
|
+
},
|
|
49
|
+
readdir: async (dir) => {
|
|
50
|
+
const names: string[] = [];
|
|
51
|
+
for (const key of [...files.keys(), ...dirs]) {
|
|
52
|
+
if (!key.startsWith(dir)) continue;
|
|
53
|
+
const rest = key.slice(dir.length);
|
|
54
|
+
if (CHILD.test(rest)) names.push(rest.slice(1));
|
|
55
|
+
}
|
|
56
|
+
return names;
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The file backend of the record store: `notebook.md` on disk, written
|
|
3
|
+
* atomically, versioned by a stat fingerprint, watched by chokidar.
|
|
4
|
+
*
|
|
5
|
+
* This is the only record module with fs/chokidar edges; record-store.ts
|
|
6
|
+
* resolves to it for every key the shell has not claimed.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { randomBytes } from "crypto";
|
|
10
|
+
import { existsSync } from "fs";
|
|
11
|
+
import * as fs from "fs/promises";
|
|
12
|
+
import chokidar, { type FSWatcher } from "chokidar";
|
|
13
|
+
import { NotebookChangedError, type RecordStore, type RecordVersion } from "./record-store";
|
|
14
|
+
|
|
15
|
+
// Per-write scratch name. A fixed `<file>.tmp` is shared by every writer, so
|
|
16
|
+
// two of them (two Orbit processes on one notebook, or one process that abandons
|
|
17
|
+
// a guarded write while another is staging one) can overwrite or delete each
|
|
18
|
+
// other's staging file and rename the wrong bytes into place. Random names cost
|
|
19
|
+
// nothing and take that off the table; paired with the `wx` flag below they also
|
|
20
|
+
// mean we never write through a path someone else got to first.
|
|
21
|
+
function tmpPathFor(filePath: string): string {
|
|
22
|
+
return `${filePath}.tmp.${randomBytes(8).toString("hex")}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Windows refuses to replace a file another rename (or a scanner) is touching
|
|
26
|
+
// at that instant, with EPERM/EACCES/EBUSY, where POSIX would just swap it in.
|
|
27
|
+
// Retrying briefly gives the same last-writer-wins outcome POSIX gets.
|
|
28
|
+
async function renameReplacing(from: string, to: string): Promise<void> {
|
|
29
|
+
for (let attempt = 0; ; attempt++) {
|
|
30
|
+
try {
|
|
31
|
+
await fs.rename(from, to);
|
|
32
|
+
return;
|
|
33
|
+
} catch (err) {
|
|
34
|
+
const code = (err as NodeJS.ErrnoException).code;
|
|
35
|
+
const transient = code === "EPERM" || code === "EACCES" || code === "EBUSY";
|
|
36
|
+
if (process.platform !== "win32" || !transient || attempt >= 10) {
|
|
37
|
+
await fs.rm(from, { force: true });
|
|
38
|
+
throw err;
|
|
39
|
+
}
|
|
40
|
+
await new Promise((r) => setTimeout(r, 10 * (attempt + 1)));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function createFileRecordStore(filePath: string): RecordStore {
|
|
46
|
+
const subscribers = new Set<(content: string) => void>();
|
|
47
|
+
let watcher: FSWatcher | null = null;
|
|
48
|
+
|
|
49
|
+
// Include dev/ino and ctimeMs, not just mtime+size: an atomic temp-and-rename
|
|
50
|
+
// save swaps the inode (changing ino), and ctime moves on any write -- so an
|
|
51
|
+
// inode-replacing or same-size rewrite with a preserved/coarse mtime is still
|
|
52
|
+
// seen as changed. #253
|
|
53
|
+
// This is the CAS key too, not only the reemit fingerprint, so a ctime-only
|
|
54
|
+
// touch (chmod, utimes, a sync client tagging xattrs) between a caller's read
|
|
55
|
+
// and its guarded write costs one retry of the loop rather than passing.
|
|
56
|
+
async function stat(): Promise<RecordVersion | null> {
|
|
57
|
+
try {
|
|
58
|
+
const st = await fs.stat(filePath);
|
|
59
|
+
return `${st.dev}:${st.ino}:${st.size}:${st.mtimeMs}:${st.ctimeMs}`;
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function startWatcher(): void {
|
|
66
|
+
// chokidar on a missing single file never emits `change`; the after-tool
|
|
67
|
+
// reemit in state.ts is the recovery path once the file appears.
|
|
68
|
+
if (!existsSync(filePath)) return;
|
|
69
|
+
try {
|
|
70
|
+
watcher = chokidar.watch(filePath, {
|
|
71
|
+
ignoreInitial: true,
|
|
72
|
+
awaitWriteFinish: {
|
|
73
|
+
stabilityThreshold: 500,
|
|
74
|
+
pollInterval: 100,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
watcher.on("change", async () => {
|
|
78
|
+
try {
|
|
79
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
80
|
+
for (const subscriber of [...subscribers]) subscriber(content);
|
|
81
|
+
} catch (err) {
|
|
82
|
+
// A file deleted between the event and the read is nothing to report.
|
|
83
|
+
if ((err as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
84
|
+
console.error("notebook watcher read failed:", err);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
} catch (err) {
|
|
89
|
+
console.error("failed to start notebook watcher:", err);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function stopWatcher(): void {
|
|
94
|
+
if (!watcher) return;
|
|
95
|
+
try {
|
|
96
|
+
watcher.close();
|
|
97
|
+
} catch {
|
|
98
|
+
/* ignore */
|
|
99
|
+
}
|
|
100
|
+
watcher = null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
kind: "file",
|
|
105
|
+
key: filePath,
|
|
106
|
+
label: filePath,
|
|
107
|
+
stat,
|
|
108
|
+
|
|
109
|
+
async read() {
|
|
110
|
+
const version = await stat();
|
|
111
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
112
|
+
return { content, version };
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Atomic write: render to a scratch sibling then rename. The rename is
|
|
117
|
+
* atomic on POSIX, so the destination either has the old or the new
|
|
118
|
+
* content -- never partial. The file watcher may still fire on the rename,
|
|
119
|
+
* but it can no longer observe a half-written file.
|
|
120
|
+
*
|
|
121
|
+
* With `expect` (a version taken *before* the read this content was derived
|
|
122
|
+
* from) the write is a compare-and-swap: if the file changed in the meantime
|
|
123
|
+
* -- an agent `edit`/`bash` append, or another writer entirely -- the write
|
|
124
|
+
* is abandoned with `NotebookChangedError` instead of overwriting a
|
|
125
|
+
* stranger's update (#391). Callers are expected to re-read and retry.
|
|
126
|
+
*
|
|
127
|
+
* The check sits between the staging write and the rename, which narrows
|
|
128
|
+
* the exposure to a single `rename` syscall but does not close it:
|
|
129
|
+
* stat-then-rename is not atomic, and a writer that lands in that gap is
|
|
130
|
+
* still overwritten. Closing it for real needs an OS-level lock (or routing
|
|
131
|
+
* every notebook write through one owner), which is a bigger change than
|
|
132
|
+
* #391.
|
|
133
|
+
*/
|
|
134
|
+
async write(content, expect) {
|
|
135
|
+
const tmp = tmpPathFor(filePath);
|
|
136
|
+
// `wx` is O_CREAT | O_EXCL: create the scratch file or fail. Never follow
|
|
137
|
+
// an existing path -- a symlink planted at a scratch name would otherwise
|
|
138
|
+
// let a write land on whatever it points at.
|
|
139
|
+
await fs.writeFile(tmp, content, { encoding: "utf-8", flag: "wx" });
|
|
140
|
+
if (expect) {
|
|
141
|
+
const current = await stat();
|
|
142
|
+
if (!current || current !== expect) {
|
|
143
|
+
await fs.rm(tmp, { force: true });
|
|
144
|
+
throw new NotebookChangedError(filePath);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
await renameReplacing(tmp, filePath);
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
async ensure() {
|
|
151
|
+
try {
|
|
152
|
+
await fs.writeFile(filePath, "", { flag: "wx" });
|
|
153
|
+
return true;
|
|
154
|
+
} catch (err) {
|
|
155
|
+
if ((err as NodeJS.ErrnoException).code !== "EEXIST") throw err;
|
|
156
|
+
}
|
|
157
|
+
// `wx` refuses to follow a symlink, so a notebook.md that links to a
|
|
158
|
+
// not-yet-created target reads as EEXIST here while stat() says absent.
|
|
159
|
+
// Creating through the link keeps that layout working as the old
|
|
160
|
+
// existsSync + writeFileSync did.
|
|
161
|
+
if ((await stat()) !== null) return false;
|
|
162
|
+
const link = await fs.lstat(filePath).catch(() => null);
|
|
163
|
+
if (!link?.isSymbolicLink()) return false;
|
|
164
|
+
await fs.writeFile(filePath, "", { flag: "w" });
|
|
165
|
+
return true;
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
onChange(cb) {
|
|
169
|
+
subscribers.add(cb);
|
|
170
|
+
if (subscribers.size === 1) startWatcher();
|
|
171
|
+
return () => {
|
|
172
|
+
if (!subscribers.delete(cb)) return;
|
|
173
|
+
if (subscribers.size === 0) stopWatcher();
|
|
174
|
+
};
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The page backend of the record store: a Galaxy page is the record. The
|
|
3
|
+
* browser shell installs one with `setRecordStore` and supplies the transport
|
|
4
|
+
* (galaxy-api.ts) it talks through; nothing here touches Node.
|
|
5
|
+
*
|
|
6
|
+
* Galaxy's page PUT has no precondition, so the compare-and-swap is a GET,
|
|
7
|
+
* a hash compare and a PUT: the same stat-then-rename window the file backend
|
|
8
|
+
* has, closed in-process by `withRecordLock` exactly as there.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { getPage, updatePage, type GalaxyPage } from "./galaxy-pages-api";
|
|
12
|
+
import { pageContentHash } from "../../shared/page-content-hash.js";
|
|
13
|
+
import { NotebookChangedError, type RecordStore, type RecordVersion } from "./record-store";
|
|
14
|
+
|
|
15
|
+
/** `content` is the embed-expanded render; `content_editor` is the source the agent edits. */
|
|
16
|
+
const body = (page: GalaxyPage): string => page.content_editor || page.content || "";
|
|
17
|
+
|
|
18
|
+
export function createPageRecordStore(opts: {
|
|
19
|
+
key: string;
|
|
20
|
+
pageId: string;
|
|
21
|
+
label?: string;
|
|
22
|
+
}): RecordStore {
|
|
23
|
+
const { key, pageId } = opts;
|
|
24
|
+
const subscribers = new Set<(content: string) => void>();
|
|
25
|
+
|
|
26
|
+
async function stat(): Promise<RecordVersion | null> {
|
|
27
|
+
try {
|
|
28
|
+
return pageContentHash(body(await getPage(pageId)));
|
|
29
|
+
} catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
kind: "page",
|
|
36
|
+
key,
|
|
37
|
+
label: opts.label ?? `Galaxy page ${pageId}`,
|
|
38
|
+
pageId,
|
|
39
|
+
stat,
|
|
40
|
+
|
|
41
|
+
async read() {
|
|
42
|
+
const content = body(await getPage(pageId));
|
|
43
|
+
return { content, version: pageContentHash(content) };
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
async write(content, expect) {
|
|
47
|
+
if (expect !== undefined) {
|
|
48
|
+
const current = await stat();
|
|
49
|
+
if (current === null || current !== expect) throw new NotebookChangedError(key);
|
|
50
|
+
}
|
|
51
|
+
await updatePage(pageId, { content, content_format: "markdown", edit_source: "agent" });
|
|
52
|
+
// Own writes are the whole feed here: chokidar reports Orbit's own file
|
|
53
|
+
// writes on the desktop, and the subscribers (widget, proposal drift,
|
|
54
|
+
// auto-push) expect to see a poller write right away. Out-of-band page
|
|
55
|
+
// edits are caught by the after-tool reemit in state.ts.
|
|
56
|
+
for (const subscriber of [...subscribers]) {
|
|
57
|
+
try {
|
|
58
|
+
subscriber(content);
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.error("record change listener failed:", err);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
// The shell binds the store to an existing page; the store never creates one.
|
|
66
|
+
async ensure() {
|
|
67
|
+
return false;
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
onChange(cb) {
|
|
71
|
+
subscribers.add(cb);
|
|
72
|
+
return () => {
|
|
73
|
+
subscribers.delete(cb);
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The record store's process-wide state: the store a shell installed and the per-key write lock.
|
|
3
|
+
*
|
|
4
|
+
* Kept apart from record-store.ts, which imports the fs-backed file store, so the in-process
|
|
5
|
+
* Galaxy tool policy (galaxy-op-policy.ts) -- which runs in the browser worker too -- can wait its
|
|
6
|
+
* turn behind the record's writers without pulling a Node module into its graph. record-store.ts
|
|
7
|
+
* re-exports all of it, so every other caller still imports from there.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { RecordStore } from "./record-store";
|
|
11
|
+
|
|
12
|
+
// The shell seam. Deliberately outside state.ts so resetState() (which every
|
|
13
|
+
// session_start runs before initSessionArtifacts) leaves it alone.
|
|
14
|
+
let installed: RecordStore | null = null;
|
|
15
|
+
|
|
16
|
+
export function setRecordStore(store: RecordStore | null): void {
|
|
17
|
+
installed = store;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function installedRecordStore(): RecordStore | null {
|
|
21
|
+
return installed;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Per-key mutex chain. Two parallel `upsertInvocationBlock` calls (e.g.
|
|
26
|
+
* `galaxy_invocation_check_all` polling several invocations concurrently)
|
|
27
|
+
* would race read-modify-write on the same record: each reads the
|
|
28
|
+
* pre-update content, applies its block, and the second writer overwrites
|
|
29
|
+
* the first. Serializing via a per-key Promise chain prevents the lost
|
|
30
|
+
* update without paying for an OS-level lock.
|
|
31
|
+
*/
|
|
32
|
+
const writeLocks = new Map<string, Promise<void>>();
|
|
33
|
+
|
|
34
|
+
export function withRecordLock<T>(key: string, work: () => Promise<T>): Promise<T> {
|
|
35
|
+
const prev = writeLocks.get(key) ?? Promise.resolve();
|
|
36
|
+
const next = prev.then(work, work);
|
|
37
|
+
// Always clear so completed locks don't pin memory; the chain is preserved
|
|
38
|
+
// through the Promise we just created.
|
|
39
|
+
writeLocks.set(
|
|
40
|
+
key,
|
|
41
|
+
next.then(
|
|
42
|
+
() => undefined,
|
|
43
|
+
() => undefined,
|
|
44
|
+
),
|
|
45
|
+
);
|
|
46
|
+
return next;
|
|
47
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The record store: one interface over the durable record.
|
|
3
|
+
*
|
|
4
|
+
* On the desktop the record is `notebook.md` in the session cwd and the backend
|
|
5
|
+
* is the file store (record-store-file.ts). Under the browser shell the record
|
|
6
|
+
* is a Galaxy page and the shell installs the page store (record-store-page.ts)
|
|
7
|
+
* with `setRecordStore`. Every reader and writer of the record resolves its
|
|
8
|
+
* store from the key `getNotebookPath()` hands out, so the callers do not know
|
|
9
|
+
* which backend they are on.
|
|
10
|
+
*
|
|
11
|
+
* This file has no Node imports of its own: the file backend is the only record
|
|
12
|
+
* module with fs/chokidar edges, and the browser's conformance test counts them.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { GalaxyApiError } from "./galaxy-api";
|
|
16
|
+
import { createFileRecordStore } from "./record-store-file";
|
|
17
|
+
import { installedRecordStore } from "./record-store-seam";
|
|
18
|
+
|
|
19
|
+
export { installedRecordStore, setRecordStore, withRecordLock } from "./record-store-seam";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Opaque, never empty; equal strings mean the record did not change between two
|
|
23
|
+
* looks. File: `dev:ino:size:mtimeMs:ctimeMs`. Page: the content hash.
|
|
24
|
+
*/
|
|
25
|
+
export type RecordVersion = string;
|
|
26
|
+
|
|
27
|
+
export interface RecordSnapshot {
|
|
28
|
+
content: string;
|
|
29
|
+
version: RecordVersion | null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface RecordStore {
|
|
33
|
+
readonly kind: "file" | "page";
|
|
34
|
+
/**
|
|
35
|
+
* `getNotebookPath()`'s string: the lock key and the anchor the side stores
|
|
36
|
+
* (activity log, template replay) hang their `dirname` off. Path-shaped under
|
|
37
|
+
* both backends.
|
|
38
|
+
*/
|
|
39
|
+
readonly key: string;
|
|
40
|
+
/** What a human or the model sees: the path, or `Galaxy page <id>`. */
|
|
41
|
+
readonly label: string;
|
|
42
|
+
/**
|
|
43
|
+
* The Galaxy page that is the record, under the page backend. The brain's update_page
|
|
44
|
+
* policy and the evidence gate compare it with a tool call's page_id to tell a write to
|
|
45
|
+
* the record from a write to some other page.
|
|
46
|
+
*/
|
|
47
|
+
readonly pageId?: string;
|
|
48
|
+
/** null when absent or unstattable; never throws. `(await stat()) !== null` is the existence check. */
|
|
49
|
+
stat(): Promise<RecordVersion | null>;
|
|
50
|
+
/** Version taken before the body. Throws the backend's own error when missing (ENOENT / GalaxyApiError 404). */
|
|
51
|
+
read(): Promise<RecordSnapshot>;
|
|
52
|
+
/**
|
|
53
|
+
* Unconditional unless `expect` is given, then a compare-and-swap: throws
|
|
54
|
+
* NotebookChangedError and leaves the record untouched when the version moved.
|
|
55
|
+
*/
|
|
56
|
+
write(content: string, expect?: RecordVersion): Promise<void>;
|
|
57
|
+
/** Create an empty record if absent; true when it created one. */
|
|
58
|
+
ensure(): Promise<boolean>;
|
|
59
|
+
/**
|
|
60
|
+
* Backend change feed (file: chokidar, own writes included; page: own writes
|
|
61
|
+
* only). Returns unsubscribe; the last unsubscribe releases the watcher.
|
|
62
|
+
*/
|
|
63
|
+
onChange(cb: (content: string) => void): () => void;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Whether `read()` failed because the record is not there, as opposed to not reachable right
|
|
68
|
+
* now. Only the first means "no record yet"; a 5xx, a timeout or a dropped connection says
|
|
69
|
+
* nothing about what the record holds.
|
|
70
|
+
*/
|
|
71
|
+
export function isRecordMissing(error: unknown): boolean {
|
|
72
|
+
if (error instanceof GalaxyApiError) return error.status === 404;
|
|
73
|
+
return (error as { code?: unknown } | null)?.code === "ENOENT";
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Thrown by a guarded `write` when the record moved under the caller. */
|
|
77
|
+
export class NotebookChangedError extends Error {
|
|
78
|
+
constructor(key: string) {
|
|
79
|
+
super(`Notebook changed on disk since it was read: ${key}`);
|
|
80
|
+
this.name = "NotebookChangedError";
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The store for a record key: the installed one when the key is its key, else
|
|
86
|
+
* a file store for that path. Resolving by key rather than by "is a store
|
|
87
|
+
* installed" keeps every test that points getNotebookPath at a real tmp file
|
|
88
|
+
* on the file backend.
|
|
89
|
+
*/
|
|
90
|
+
export function recordStore(key: string): RecordStore {
|
|
91
|
+
const installed = installedRecordStore();
|
|
92
|
+
if (installed && installed.key === key) return installed;
|
|
93
|
+
return createFileRecordStore(key);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* How many times a guarded update re-reads and retries before giving up. A
|
|
98
|
+
* write only loses the version check when someone else wrote in the
|
|
99
|
+
* microseconds between our read and our write; three attempts is far more than
|
|
100
|
+
* convergence needs, and bounding it keeps a pathological writer from spinning
|
|
101
|
+
* us.
|
|
102
|
+
*/
|
|
103
|
+
export const MAX_CAS_ATTEMPTS = 3;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Read -> apply -> write as a compare-and-swap, retrying against fresh content
|
|
107
|
+
* when the record moved under us.
|
|
108
|
+
*
|
|
109
|
+
* This is the discipline the poller already writes under (#391), packaged for
|
|
110
|
+
* the callers that mutate a block from outside a poll. An unguarded whole-record
|
|
111
|
+
* write renders the record from content captured before whatever landed in
|
|
112
|
+
* between -- a poll advancing a block, an agent `edit`, a `bash` append -- and
|
|
113
|
+
* the in-process lock cannot help, because it only orders Orbit's own writers.
|
|
114
|
+
*
|
|
115
|
+
* Call with the record lock held. `read()` takes the version *before* the body
|
|
116
|
+
* on purpose: a version taken afterwards would let a write that landed in
|
|
117
|
+
* between look unchanged, which is the exact clobber this prevents, while
|
|
118
|
+
* taking it first can only ever cost a spurious retry.
|
|
119
|
+
*
|
|
120
|
+
* `apply` runs against each attempt's fresh content and may throw to abandon
|
|
121
|
+
* the update outright -- a validation that depends on what the record says now
|
|
122
|
+
* belongs inside it, not before the loop.
|
|
123
|
+
*/
|
|
124
|
+
export async function withRecordCas<T>(
|
|
125
|
+
store: RecordStore,
|
|
126
|
+
apply: (content: string) => { content: string; result: T },
|
|
127
|
+
): Promise<T> {
|
|
128
|
+
let lastError: unknown;
|
|
129
|
+
for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
|
|
130
|
+
// A record that's actually gone or unreadable fails here with its own
|
|
131
|
+
// ENOENT/EACCES/404 instead of being dressed up as a race.
|
|
132
|
+
const { content: fresh, version } = await store.read();
|
|
133
|
+
// Readable but unversioned: without a version there's no compare-and-swap,
|
|
134
|
+
// and an unguarded whole-record write is the thing this exists to stop.
|
|
135
|
+
if (!version) {
|
|
136
|
+
lastError = new NotebookChangedError(store.key);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
const { content, result } = apply(fresh);
|
|
140
|
+
try {
|
|
141
|
+
await store.write(content, version);
|
|
142
|
+
return result;
|
|
143
|
+
} catch (error) {
|
|
144
|
+
if (!(error instanceof NotebookChangedError)) throw error;
|
|
145
|
+
lastError = error;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
throw lastError;
|
|
149
|
+
}
|