calkit-python 0.41.17__tar.gz → 0.41.18__tar.gz
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.
- {calkit_python-0.41.17 → calkit_python-0.41.18}/PKG-INFO +1 -1
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/scheduler.py +61 -30
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/cli/test_scheduler.py +49 -18
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/src/extension.ts +92 -2
- calkit_python-0.41.18/vscode-ext/src/pipeline/core.ts +173 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/src/sidebar.ts +140 -10
- calkit_python-0.41.18/vscode-ext/src/test/pipeline.test.ts +150 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/src/types.ts +12 -0
- calkit_python-0.41.17/vscode-ext/src/pipeline/core.ts +0 -81
- calkit_python-0.41.17/vscode-ext/src/test/pipeline.test.ts +0 -61
- {calkit_python-0.41.17 → calkit_python-0.41.18}/.claude-plugin/marketplace.json +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/.gitattributes +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/.gitignore +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/.pre-commit-config.yaml +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/.prettierignore +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/.prettierrc.json +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/.python-version +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/.vscode/launch.json +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/.vscode/tasks.json +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/AGENTS.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/CITATION.cff +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/CODE_OF_CONDUCT.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/CONTRIBUTING.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/LICENSE +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/Makefile +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/README.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/agent-plugin/.claude-plugin/plugin.json +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/agent-plugin/skills/add-pipeline-stage/SKILL.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/agent-plugin/skills/conventions/SKILL.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/agent-plugin/skills/create-pipeline/SKILL.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/__init__.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/__main__.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/calc.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/check.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/__init__.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/check.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/cloud.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/config.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/core.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/delete.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/describe.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/dev.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/import_.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/latex.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/list.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/main/__init__.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/main/core.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/main/xr.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/new.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/notebooks.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/office.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/overleaf.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cli/update.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/cloud.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/conda.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/config.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/core.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/datasets.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/dependencies.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/detect.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/docker.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/dvc/__init__.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/dvc/core.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/dvc/zip.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/environments.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/fs.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/git.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/github.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/gui.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/install.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/invenio.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/julia.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/jupyter.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/jupyterlab/__init__.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/jupyterlab/routes.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/labextension/package.json +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/labextension/schemas/calkit/package.json.orig +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/labextension/schemas/calkit/plugin.json +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/labextension/static/502.9a2c5772a15466e923ef.js +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/labextension/static/695.2c41003a452d43d2b358.js +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/labextension/static/867.a42a046aa5108f54f8fb.js +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/labextension/static/909.e3f9cc3408834a7fdcc3.js +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js.LICENSE.txt +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/labextension/static/b2f1c3efe70cb539d121.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/labextension/static/remoteEntry.ac9035764d5b2adbb542.js +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/labextension/static/style.js +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/labextension/static/third-party-licenses.json +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/licenses.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/magics.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/matlab.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/models/__init__.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/models/core.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/models/io.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/models/iteration.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/models/pipeline.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/notebooks.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/office.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/ops.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/overleaf.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/pipeline.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/releases.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/server.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/templates/__init__.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/templates/core.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/templates/latex/__init__.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/templates/latex/article/paper.tex +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/templates/latex/core.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/templates/latex/jfm/jfm.bst +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/templates/latex/jfm/jfm.cls +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/templates/latex/jfm/lineno-FLM.sty +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/templates/latex/jfm/paper.tex +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/templates/latex/jfm/upmath.sty +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/__init__.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/cli/__init__.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/cli/main/__init__.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/cli/main/test_core.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/cli/main/test_lock.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/cli/main/test_subprojects.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/cli/main/test_xr.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/cli/test_check.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/cli/test_cloud.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/cli/test_config.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/cli/test_delete.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/cli/test_import.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/cli/test_latex.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/cli/test_list.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/cli/test_new.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/cli/test_notebooks.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/cli/test_overleaf.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/cli/test_update.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/dvc/__init__.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/dvc/test_core.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/dvc/test_zip.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/jupyterlab/__init__.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/jupyterlab/conftest.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/jupyterlab/test_routes.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/models/__init__.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/models/test_core.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/models/test_iteration.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/models/test_pipeline.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_calc.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_check.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_cloud.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_conda.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_core.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_dependencies.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_detect.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_docker.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_environments.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_fs.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_git.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_install.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_invenio.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_julia.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_jupyter.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_licenses.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_magics.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_matlab.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_notebooks.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_pipeline.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_releases.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/calkit/tests/test_templates.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/CNAME +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/acknowledgements.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/ai-tools.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/apps.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/calculations.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/calkit-yaml.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/cli-reference.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/cloud-integration.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/datasets.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/dependencies.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/environments.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/examples.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/governance.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/help.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/hpc.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/img/c-to-the-k-white.svg +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/img/calkit-fragmentation-compendium.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/img/calkit-no-bg.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/img/caltech.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/img/connect-zenodo.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/img/jupyterlab/all-green.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/img/jupyterlab/collect-data-stale.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/img/jupyterlab/new-env.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/img/jupyterlab/new-notebook.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/img/jupyterlab/pipeline-badge.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/img/jupyterlab-params.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/img/pipeline.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/img/plos-osi-code-2024-03.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/img/schmidt-sciences.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/img/vscode-nb-params.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/index.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/installation.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/jupyterlab.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/local-server.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/notebooks.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/overleaf.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/pipeline/index.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/pipeline/manual-steps.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/pipeline/running-and-logging.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/quickstart.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/references.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/releases.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/reproducibility.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/subprojects.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/adding-latex-pub-docker.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/ai-agents.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/conda-envs.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/existing-project.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/first-project.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/github-actions.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/actions-repo-secrets.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/latex-codespaces/building-codespace.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/latex-codespaces/codespaces-secrets-2.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/latex-codespaces/editor-split.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/latex-codespaces/go-to-linked-code.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/latex-codespaces/issue-from-selection.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/latex-codespaces/new-project.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/latex-codespaces/new-pub-2.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/latex-codespaces/new-token.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/latex-codespaces/paper.tex.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/latex-codespaces/project-home-3.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/latex-codespaces/push.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/latex-codespaces/stage.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/office/anakin-excel.jpg +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/office/chart-more-rows.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/office/create-project.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/office/elsevier-research-data-guidelines.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/office/excel-chart.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/office/excel-data.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/office/insert-link-to-file.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/office/needs-clone.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/office/new-stage.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/office/phd-comics-version-control.webp +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/office/pipeline-out-of-date.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/office/status-more-rows.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/office/uncommitted-changes.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/office/untracked-data.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/office/updated-publication.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/office/word-to-pdf-stage-2.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/office/workflow-page.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/openfoam/clone.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/openfoam/create-project.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/openfoam/datasets-page.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/openfoam/figure-on-website-updated.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/openfoam/figure-on-website.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/openfoam/new-token.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/openfoam/reclone.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/openfoam/status-after-import-dataset.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/quick-actions.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/run-proc.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/vscode-slurm-notebook/create-calkit-env.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/vscode-slurm-notebook/create-inner-env.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/vscode-slurm-notebook/create-new-calkit-env.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/vscode-slurm-notebook/select-calkit-env.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/vscode-slurm-notebook/slurm-job-running.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/vscode-slurm-notebook/slurm-launch-options.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/img/vscode-slurm-notebook/starting-slurm-job.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/index.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/jupyterlab.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/latex-codespaces.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/matlab.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/notebook-pipeline.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/office.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/openfoam.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/procedures.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/tutorials/vscode-slurm-notebook.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/docs/version-control.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/flake.lock +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/flake.nix +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/.yarnrc.yml +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/babel.config.js +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/install.json +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/jest.config.js +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/jupyter-config/server-config/calkit.json +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/package.json +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/schema/plugin.json +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/__tests__/useQueries.spec.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/calkit-config.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/cell-output-marker.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/components/commit-dialog.tsx +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/components/environment-editor.tsx +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/components/notebook-registration.tsx +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/components/notebook-toolbar.tsx +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/components/pipeline-status-bar.tsx +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/components/project-info-editor.tsx +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/components/sidebar-settings.tsx +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/components/sidebar.tsx +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/components/stage-editor.tsx +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/feature-flags.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/file-browser-menu.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/hooks/__tests__/useQueries.test.tsx +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/hooks/useQueries.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/icons.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/index.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/io-tracker.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/pipeline-state.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/queryClient.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/request.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/src/shims-mainmenu.d.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/style/base.css +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/style/cell-output-marker.css +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/style/environment-editor.css +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/style/environment-selector.css +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/style/img/calkit-no-bg.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/style/index.css +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/style/index.js +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/style/notebook-toolbar.css +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/style/pipeline-status-bar.css +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/style/sidebar.css +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/tsconfig.json +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/tsconfig.test.json +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/ui-tests/.gitignore +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/ui-tests/README.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/ui-tests/jupyter_server_test_config.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/ui-tests/package.json +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/ui-tests/playwright.config.js +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/ui-tests/tests/calkit.spec.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/ui-tests/yarn.lock +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/jupyterlab-ext/yarn.lock +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/mkdocs.yml +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/pyproject.toml +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/scripts/generate-docs-references.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/scripts/install.ps1 +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/scripts/install.sh +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/scripts/make-calk9.sh +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/scripts/sync-docs.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/test/dvc-md5-dir/osx-arm64.txt +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/test/nb-julia.ipynb +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/test/nb-params.ipynb +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/test/nb-subdir.ipynb +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/test/pipeline.ipynb +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/test/script.py +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/test/test-log.log +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/uv.lock +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/.gitignore +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/.vscodeignore +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/CHANGELOG.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/LICENSE +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/README.md +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/images/calkit-icon.svg +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/images/calkit-no-bg.png +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/package-lock.json +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/package.json +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/scripts/set-proposed-api.js +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/src/environments.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/src/figures/core.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/src/figures/view.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/src/notebooks.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/src/test/environments.test.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/src/test/figures.test.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/src/test/kernel-selection.test.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/src/test/notebooks.test.ts +0 -0
- {calkit_python-0.41.17 → calkit_python-0.41.18}/vscode-ext/tsconfig.json +0 -0
|
@@ -304,6 +304,25 @@ def _slurm_exit_code(job_id: str) -> int | None:
|
|
|
304
304
|
return None
|
|
305
305
|
|
|
306
306
|
|
|
307
|
+
def _parse_pbs_state(stdout: str) -> tuple[str | None, int | None]:
|
|
308
|
+
# `qstat -f` output is a flat list of `key = value` lines; pull out the
|
|
309
|
+
# job's state and, for a finished job, its exit status. The status field is
|
|
310
|
+
# spelled `Exit_status` on PBS Pro and `exit_status` on some Torque builds,
|
|
311
|
+
# so match it case-insensitively.
|
|
312
|
+
state = None
|
|
313
|
+
exit_code = None
|
|
314
|
+
for line in stdout.splitlines():
|
|
315
|
+
stripped = line.strip()
|
|
316
|
+
if stripped.startswith("job_state"):
|
|
317
|
+
state = stripped.split("=", 1)[-1].strip()
|
|
318
|
+
elif stripped.lower().startswith("exit_status"):
|
|
319
|
+
try:
|
|
320
|
+
exit_code = int(stripped.split("=", 1)[-1].strip())
|
|
321
|
+
except ValueError:
|
|
322
|
+
exit_code = None
|
|
323
|
+
return state, exit_code
|
|
324
|
+
|
|
325
|
+
|
|
307
326
|
def _poll_job(kind: str, job_id: str) -> tuple[bool, int | None]:
|
|
308
327
|
"""Return ``(active, exit_code)`` for a scheduler job.
|
|
309
328
|
|
|
@@ -339,39 +358,51 @@ def _poll_job(kind: str, job_id: str) -> tuple[bool, int | None]:
|
|
|
339
358
|
if "invalid job id" in stderr:
|
|
340
359
|
return False, _slurm_exit_code(job_id)
|
|
341
360
|
return True, None
|
|
342
|
-
#
|
|
343
|
-
#
|
|
344
|
-
#
|
|
345
|
-
#
|
|
346
|
-
#
|
|
361
|
+
# PBS reports a finished job differently across variants, so poll in two
|
|
362
|
+
# steps that mirror the SLURM path above. First consult the active-queue
|
|
363
|
+
# view with `qstat -f`: every live state (R, Q, H, E) shows here, and on
|
|
364
|
+
# Torque a completed job lingers here in state `C` carrying its
|
|
365
|
+
# `Exit_status`. `qstat -f` is used rather than plain `qstat <id>` because
|
|
366
|
+
# the latter exits 0 even for completed jobs, so the return code alone
|
|
367
|
+
# could not tell running from done.
|
|
347
368
|
p = subprocess.run(
|
|
348
369
|
["qstat", "-f", job_id], capture_output=True, text=True, check=False
|
|
349
370
|
)
|
|
350
|
-
if p.returncode
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
371
|
+
if p.returncode == 0:
|
|
372
|
+
state, exit_code = _parse_pbs_state(p.stdout)
|
|
373
|
+
if state in ("C", "F"):
|
|
374
|
+
return False, exit_code
|
|
375
|
+
if state is not None:
|
|
376
|
+
return True, None
|
|
377
|
+
# The job is no longer in the active queue---on PBS Pro a finished job is
|
|
378
|
+
# hidden from plain `qstat` and shows (as state `F` with its `Exit_status`)
|
|
379
|
+
# only under `qstat -x`---or qstat failed. Ask the history view for the
|
|
380
|
+
# finished record. Without this, a PBS Pro job that has finished is never
|
|
381
|
+
# seen as done and the wait hangs forever. `-x` means "include finished
|
|
382
|
+
# jobs" on PBS Pro; on Torque it switches qstat to XML output, which simply
|
|
383
|
+
# won't parse here, leaving the stderr check below to settle it (Torque
|
|
384
|
+
# already reported completion above via state `C`).
|
|
385
|
+
hist = subprocess.run(
|
|
386
|
+
["qstat", "-x", "-f", job_id],
|
|
387
|
+
capture_output=True,
|
|
388
|
+
text=True,
|
|
389
|
+
check=False,
|
|
390
|
+
)
|
|
391
|
+
if hist.returncode == 0:
|
|
392
|
+
state, exit_code = _parse_pbs_state(hist.stdout)
|
|
393
|
+
if state in ("C", "F"):
|
|
394
|
+
return False, exit_code
|
|
395
|
+
if state is not None:
|
|
396
|
+
return True, None
|
|
397
|
+
# Neither view resolved a state. A non-zero exit is ambiguous: either the
|
|
398
|
+
# job is gone (finished and purged from history) or qstat failed
|
|
399
|
+
# transiently---a busy PBS server periodically refuses connections or times
|
|
400
|
+
# out. Treating a transient failure as completion would stop the wait while
|
|
401
|
+
# the job is still running and writing its log, so only conclude the job is
|
|
402
|
+
# done when qstat positively reports it is unknown; otherwise keep waiting.
|
|
403
|
+
# A purged job is done but with an unknowable exit status.
|
|
404
|
+
stderr = (p.stderr or "").lower()
|
|
405
|
+
return ("unknown job" not in stderr), None
|
|
375
406
|
|
|
376
407
|
|
|
377
408
|
def _is_active(kind: str, job_id: str) -> bool:
|
|
@@ -215,44 +215,75 @@ def test_poll_job_pbs(monkeypatch):
|
|
|
215
215
|
|
|
216
216
|
import calkit.cli.scheduler as sched
|
|
217
217
|
|
|
218
|
-
|
|
218
|
+
# PBS is polled in two steps: plain `qstat -f` for the active queue, then
|
|
219
|
+
# `qstat -x -f` for the finished-job history view. The fake dispatches on
|
|
220
|
+
# whether `-x` is present so each step can be simulated independently, the
|
|
221
|
+
# way a real PBS Pro server answers them.
|
|
222
|
+
active: dict = {}
|
|
223
|
+
history: dict = {}
|
|
219
224
|
|
|
220
|
-
def _fake_run(*args, **kwargs):
|
|
225
|
+
def _fake_run(cmd, *args, **kwargs):
|
|
226
|
+
outcomes = history if "-x" in cmd else active
|
|
221
227
|
return subprocess.CompletedProcess(
|
|
222
|
-
|
|
228
|
+
cmd,
|
|
223
229
|
returncode=outcomes["returncode"],
|
|
224
230
|
stdout=outcomes.get("stdout", ""),
|
|
225
231
|
stderr=outcomes.get("stderr", ""),
|
|
226
232
|
)
|
|
227
233
|
|
|
228
234
|
monkeypatch.setattr(sched.subprocess, "run", _fake_run)
|
|
229
|
-
# A running job (state R) is active with no exit code yet
|
|
230
|
-
|
|
235
|
+
# A running job (state R) is active with no exit code yet, and resolves
|
|
236
|
+
# from the active queue alone---the history view is never consulted.
|
|
237
|
+
active.update(returncode=0, stdout=" job_state = R\n", stderr="")
|
|
238
|
+
history.clear()
|
|
231
239
|
assert _poll_job("pbs", "1.pbs") == (True, None)
|
|
232
|
-
#
|
|
233
|
-
#
|
|
234
|
-
#
|
|
235
|
-
|
|
240
|
+
# The reported bug: on PBS Pro a finished job leaves the active queue and
|
|
241
|
+
# is shown only under `qstat -x`, where it appears as state F with its
|
|
242
|
+
# Exit_status. Plain `qstat -f` errors with a message that is NOT "unknown
|
|
243
|
+
# job", which used to be read as "still active" and hang the wait forever.
|
|
244
|
+
active.update(
|
|
245
|
+
returncode=1,
|
|
246
|
+
stdout="",
|
|
247
|
+
stderr="qstat: 1.pbs Job has finished, use -x to obtain historical "
|
|
248
|
+
"job information\n",
|
|
249
|
+
)
|
|
250
|
+
history.update(
|
|
236
251
|
returncode=0, stdout=" job_state = F\n Exit_status = 0\n"
|
|
237
252
|
)
|
|
238
253
|
assert _poll_job("pbs", "1.pbs") == (False, 0)
|
|
239
|
-
|
|
254
|
+
# A non-zero exit code from the finished job is reported back so the caller
|
|
255
|
+
# can fail the stage.
|
|
256
|
+
history.update(
|
|
257
|
+
returncode=0, stdout=" job_state = F\n Exit_status = 137\n"
|
|
258
|
+
)
|
|
259
|
+
assert _poll_job("pbs", "1.pbs") == (False, 137)
|
|
260
|
+
# On Torque a completed job lingers in the active queue as state C with its
|
|
261
|
+
# exit status, so it is done without ever needing the history view.
|
|
262
|
+
active.update(
|
|
240
263
|
returncode=0, stdout=" job_state = C\n exit_status = 137\n"
|
|
241
264
|
)
|
|
265
|
+
history.update(returncode=1, stdout="", stderr="should not be reached\n")
|
|
242
266
|
assert _poll_job("pbs", "1.pbs") == (False, 137)
|
|
243
267
|
# A finished job whose record lacks an exit status yields an unknown code.
|
|
244
|
-
|
|
268
|
+
active.update(returncode=1, stdout="", stderr="qstat: Unknown Job Id\n")
|
|
269
|
+
history.update(returncode=0, stdout=" job_state = F\n")
|
|
245
270
|
assert _poll_job("pbs", "1.pbs") == (False, None)
|
|
246
|
-
# Once purged
|
|
247
|
-
# with no way to recover the exit status.
|
|
248
|
-
|
|
271
|
+
# Once purged from history too, both views error with "unknown job": done,
|
|
272
|
+
# but with no way to recover the exit status.
|
|
273
|
+
active.update(
|
|
274
|
+
returncode=1, stdout="", stderr="qstat: Unknown Job Id 1.pbs\n"
|
|
275
|
+
)
|
|
276
|
+
history.update(
|
|
249
277
|
returncode=1, stdout="", stderr="qstat: Unknown Job Id 1.pbs\n"
|
|
250
278
|
)
|
|
251
279
|
assert _poll_job("pbs", "1.pbs") == (False, None)
|
|
252
|
-
# A transient qstat failure (busy/unreachable server) is NOT
|
|
253
|
-
# treating it as done would stop the wait while the job still
|
|
254
|
-
# job is reported active and the caller keeps polling.
|
|
255
|
-
|
|
280
|
+
# A transient qstat failure (busy/unreachable server) on both views is NOT
|
|
281
|
+
# completion: treating it as done would stop the wait while the job still
|
|
282
|
+
# runs, so the job is reported active and the caller keeps polling.
|
|
283
|
+
active.update(
|
|
284
|
+
returncode=1, stdout="", stderr="qstat: cannot connect to server\n"
|
|
285
|
+
)
|
|
286
|
+
history.update(
|
|
256
287
|
returncode=1, stdout="", stderr="qstat: cannot connect to server\n"
|
|
257
288
|
)
|
|
258
289
|
assert _poll_job("pbs", "1.pbs") == (True, None)
|
|
@@ -24,7 +24,12 @@ import {
|
|
|
24
24
|
getConfiguredCandidateForNotebookPath as resolveConfiguredCandidateForNotebookPath,
|
|
25
25
|
getExecutedNotebookHtmlPath,
|
|
26
26
|
} from "./notebooks";
|
|
27
|
-
import type {
|
|
27
|
+
import type {
|
|
28
|
+
CalkitInfo,
|
|
29
|
+
DvcYaml,
|
|
30
|
+
EnvDescription,
|
|
31
|
+
StaleStageDetail,
|
|
32
|
+
} from "./types";
|
|
28
33
|
import { dvcStageOutputPaths } from "./pipeline/core";
|
|
29
34
|
import { CalkitSidebarProvider } from "./sidebar";
|
|
30
35
|
import {
|
|
@@ -142,6 +147,10 @@ let hasCheckedCalkitCli = false;
|
|
|
142
147
|
const pipelineOutputUris = new Set<string>();
|
|
143
148
|
const staleOutputUris = new Set<string>();
|
|
144
149
|
const staleStageNames = new Set<string>();
|
|
150
|
+
// What is stale about each stale stage (modified inputs/outputs, script,
|
|
151
|
+
// environment, command), keyed by base stage name. Surfaced as per-property
|
|
152
|
+
// markers under a stale stage in the sidebar.
|
|
153
|
+
let staleStageDetails: Record<string, StaleStageDetail> = {};
|
|
145
154
|
// Stages currently being executed by an in-progress `calkit run` (reported by
|
|
146
155
|
// `calkit status --json` as pipeline.running_stages); shown with a spinner.
|
|
147
156
|
const runningStageNames = new Set<string>();
|
|
@@ -1228,6 +1237,29 @@ export function activate(context: vscode.ExtensionContext): void {
|
|
|
1228
1237
|
}),
|
|
1229
1238
|
);
|
|
1230
1239
|
|
|
1240
|
+
// Re-check pipeline status when a workspace file is saved, so a stage goes
|
|
1241
|
+
// stale in the sidebar right after editing its script/input/notebook without
|
|
1242
|
+
// a manual refresh (issue #959). The dvc.yaml/calkit.yaml watchers already
|
|
1243
|
+
// cover config edits. The scheduled refresh is debounced and only runs
|
|
1244
|
+
// `calkit status` when auto-refresh is enabled.
|
|
1245
|
+
const onDocumentSaved = (uri: vscode.Uri): void => {
|
|
1246
|
+
const root = getWorkspaceRoot();
|
|
1247
|
+
if (!root || uri.scheme !== "file") {
|
|
1248
|
+
return;
|
|
1249
|
+
}
|
|
1250
|
+
const rel = path.relative(root, uri.fsPath);
|
|
1251
|
+
if (rel.startsWith("..") || path.isAbsolute(rel)) {
|
|
1252
|
+
return; // saved file is outside the workspace
|
|
1253
|
+
}
|
|
1254
|
+
scheduleRefreshPipelineOutputContext(context);
|
|
1255
|
+
};
|
|
1256
|
+
context.subscriptions.push(
|
|
1257
|
+
vscode.workspace.onDidSaveTextDocument((doc) => onDocumentSaved(doc.uri)),
|
|
1258
|
+
vscode.workspace.onDidSaveNotebookDocument((doc) =>
|
|
1259
|
+
onDocumentSaved(doc.uri),
|
|
1260
|
+
),
|
|
1261
|
+
);
|
|
1262
|
+
|
|
1231
1263
|
// Image/figure files open in a custom editor, so the active-text-editor event
|
|
1232
1264
|
// above doesn't fire for them. Re-evaluate the figure-output context on tab
|
|
1233
1265
|
// changes (a tab becoming active) and tab-group changes (the active split
|
|
@@ -1940,6 +1972,7 @@ function renderSidebarFromState(): void {
|
|
|
1940
1972
|
currentDetectedResults,
|
|
1941
1973
|
currentDetectedPresentations,
|
|
1942
1974
|
getHiddenSections(),
|
|
1975
|
+
staleStageDetails,
|
|
1943
1976
|
);
|
|
1944
1977
|
updateSidebarBadge();
|
|
1945
1978
|
}
|
|
@@ -1949,6 +1982,7 @@ function renderSidebarFromState(): void {
|
|
|
1949
1982
|
function applyStaleStages(
|
|
1950
1983
|
workspaceRoot: string,
|
|
1951
1984
|
freshStaleStageNames: Set<string>,
|
|
1985
|
+
freshStaleStageDetails: Record<string, StaleStageDetail> = {},
|
|
1952
1986
|
): void {
|
|
1953
1987
|
const outputMap = buildPipelineOutputMapFromYaml(
|
|
1954
1988
|
workspaceRoot,
|
|
@@ -1970,6 +2004,8 @@ function applyStaleStages(
|
|
|
1970
2004
|
for (const n of freshStaleStageNames) {
|
|
1971
2005
|
staleStageNames.add(n);
|
|
1972
2006
|
}
|
|
2007
|
+
const prevDetails = staleStageDetails;
|
|
2008
|
+
staleStageDetails = freshStaleStageDetails;
|
|
1973
2009
|
const changedUris = [...new Set([...prevStale, ...staleOutputUris])].map(
|
|
1974
2010
|
(p) => vscode.Uri.file(p),
|
|
1975
2011
|
);
|
|
@@ -1978,7 +2014,10 @@ function applyStaleStages(
|
|
|
1978
2014
|
}
|
|
1979
2015
|
const staleChanged =
|
|
1980
2016
|
prevStageNames.size !== staleStageNames.size ||
|
|
1981
|
-
[...staleStageNames].some((n) => !prevStageNames.has(n))
|
|
2017
|
+
[...staleStageNames].some((n) => !prevStageNames.has(n)) ||
|
|
2018
|
+
// The set of stale stages can be unchanged while *what* is stale about them
|
|
2019
|
+
// changes (e.g. a different input edited), so compare the details too.
|
|
2020
|
+
JSON.stringify(prevDetails) !== JSON.stringify(staleStageDetails);
|
|
1982
2021
|
if (staleChanged) {
|
|
1983
2022
|
renderSidebarFromState();
|
|
1984
2023
|
}
|
|
@@ -2010,6 +2049,55 @@ let runStatusPolling = false;
|
|
|
2010
2049
|
let suppressRwlockUntil = 0;
|
|
2011
2050
|
const RUN_STATUS_POLL_INTERVAL_MS = 2500;
|
|
2012
2051
|
|
|
2052
|
+
function unionPaths(
|
|
2053
|
+
a: string[] | undefined,
|
|
2054
|
+
b: string[] | undefined,
|
|
2055
|
+
): string[] {
|
|
2056
|
+
return [...new Set([...(a ?? []), ...(b ?? [])])];
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
// Merge the per-stage staleness detail from `calkit status --json` down to base
|
|
2060
|
+
// stage names. iterate_over stages report one entry per expansion
|
|
2061
|
+
// ("benchmark@zdt1"); the sidebar keys stages by the base name, so union each
|
|
2062
|
+
// expansion's modified paths/flags under "benchmark".
|
|
2063
|
+
function collapseStaleStageDetails(
|
|
2064
|
+
raw: Record<string, StaleStageDetail>,
|
|
2065
|
+
): Record<string, StaleStageDetail> {
|
|
2066
|
+
const merged: Record<string, StaleStageDetail> = {};
|
|
2067
|
+
for (const [key, detail] of Object.entries(raw)) {
|
|
2068
|
+
const base = key.split("@")[0];
|
|
2069
|
+
const existing = merged[base];
|
|
2070
|
+
if (!existing) {
|
|
2071
|
+
merged[base] = {
|
|
2072
|
+
stale_outputs: [...(detail.stale_outputs ?? [])],
|
|
2073
|
+
modified_inputs: [...(detail.modified_inputs ?? [])],
|
|
2074
|
+
modified_outputs: [...(detail.modified_outputs ?? [])],
|
|
2075
|
+
modified_command: !!detail.modified_command,
|
|
2076
|
+
always_run: !!detail.always_run,
|
|
2077
|
+
is_subproject: !!detail.is_subproject,
|
|
2078
|
+
};
|
|
2079
|
+
continue;
|
|
2080
|
+
}
|
|
2081
|
+
existing.stale_outputs = unionPaths(
|
|
2082
|
+
existing.stale_outputs,
|
|
2083
|
+
detail.stale_outputs,
|
|
2084
|
+
);
|
|
2085
|
+
existing.modified_inputs = unionPaths(
|
|
2086
|
+
existing.modified_inputs,
|
|
2087
|
+
detail.modified_inputs,
|
|
2088
|
+
);
|
|
2089
|
+
existing.modified_outputs = unionPaths(
|
|
2090
|
+
existing.modified_outputs,
|
|
2091
|
+
detail.modified_outputs,
|
|
2092
|
+
);
|
|
2093
|
+
existing.modified_command =
|
|
2094
|
+
existing.modified_command || !!detail.modified_command;
|
|
2095
|
+
existing.always_run = existing.always_run || !!detail.always_run;
|
|
2096
|
+
existing.is_subproject = existing.is_subproject || !!detail.is_subproject;
|
|
2097
|
+
}
|
|
2098
|
+
return merged;
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2013
2101
|
async function pollPipelineRunStatus(
|
|
2014
2102
|
context: vscode.ExtensionContext,
|
|
2015
2103
|
): Promise<void> {
|
|
@@ -2032,6 +2120,7 @@ async function pollPipelineRunStatus(
|
|
|
2032
2120
|
running?: boolean;
|
|
2033
2121
|
running_stages?: string[];
|
|
2034
2122
|
stale_stage_names?: string[];
|
|
2123
|
+
stale_stages?: Record<string, StaleStageDetail>;
|
|
2035
2124
|
};
|
|
2036
2125
|
};
|
|
2037
2126
|
const pipeline = status?.pipeline ?? {};
|
|
@@ -2057,6 +2146,7 @@ async function pollPipelineRunStatus(
|
|
|
2057
2146
|
new Set(
|
|
2058
2147
|
(pipeline.stale_stage_names ?? []).map((name) => name.split("@")[0]),
|
|
2059
2148
|
),
|
|
2149
|
+
collapseStaleStageDetails(pipeline.stale_stages ?? {}),
|
|
2060
2150
|
);
|
|
2061
2151
|
}
|
|
2062
2152
|
} catch (error) {
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import type { DvcStage, StaleStageDetail } from "../types";
|
|
2
|
+
|
|
3
|
+
// Pure helpers (no vscode imports) for resolving pipeline stage outputs, so they
|
|
4
|
+
// can be unit-tested under plain `node --test` (where the `vscode` module is
|
|
5
|
+
// absent). The crux is iterate_over (DVC "matrix") stages: calkit writes their
|
|
6
|
+
// deps/outs templated with `${item.*}` placeholders plus a `matrix` of values,
|
|
7
|
+
// so the literal templated path never exists on disk and the concrete
|
|
8
|
+
// per-iteration files would otherwise go unrecognized as pipeline outputs.
|
|
9
|
+
|
|
10
|
+
// Expand a DVC `matrix` into the list of concrete `${item.*}` substitution maps,
|
|
11
|
+
// one per cartesian-product combination. Mirrors calkit's `_expand_matrix` in
|
|
12
|
+
// calkit/pipeline.py, including flattening nested-dict values (produced by
|
|
13
|
+
// list-of-lists iterations) into dotted "parent.child" keys.
|
|
14
|
+
export function expandDvcMatrix(
|
|
15
|
+
matrix: Record<string, unknown[]>,
|
|
16
|
+
): Record<string, string>[] {
|
|
17
|
+
let combos: Record<string, unknown>[] = [{}];
|
|
18
|
+
for (const [key, values] of Object.entries(matrix)) {
|
|
19
|
+
// calkit always writes matrix values as arrays, but a hand-edited dvc.yaml
|
|
20
|
+
// could hold a scalar (which would iterate characters) or a non-iterable
|
|
21
|
+
// (which would throw); skip anything that isn't an array so a malformed
|
|
22
|
+
// file can't break the sidebar render.
|
|
23
|
+
if (!Array.isArray(values)) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const next: Record<string, unknown>[] = [];
|
|
27
|
+
for (const combo of combos) {
|
|
28
|
+
for (const value of values) {
|
|
29
|
+
next.push({ ...combo, [key]: value });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
combos = next;
|
|
33
|
+
}
|
|
34
|
+
return combos.map((combo) => {
|
|
35
|
+
const flat: Record<string, string> = {};
|
|
36
|
+
for (const [key, value] of Object.entries(combo)) {
|
|
37
|
+
// A nested-dict value substitutes `${item.key.subkey}`; any other value
|
|
38
|
+
// is a scalar substituting `${item.key}`.
|
|
39
|
+
if (value !== null && typeof value === "object") {
|
|
40
|
+
for (const [subKey, subVal] of Object.entries(
|
|
41
|
+
value as Record<string, unknown>,
|
|
42
|
+
)) {
|
|
43
|
+
flat[`${key}.${subKey}`] = String(subVal);
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
flat[key] = String(value);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return flat;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Substitute one matrix combination's `${item.*}` placeholders into a template.
|
|
54
|
+
function applyMatrixItem(
|
|
55
|
+
template: string,
|
|
56
|
+
item: Record<string, string>,
|
|
57
|
+
): string {
|
|
58
|
+
let result = template;
|
|
59
|
+
for (const [variable, value] of Object.entries(item)) {
|
|
60
|
+
result = result.split(`\${item.${variable}}`).join(value);
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// The concrete output paths declared by a DVC stage. A plain stage returns its
|
|
66
|
+
// `outs` as written; an iterate_over (matrix) stage has its templated `outs`
|
|
67
|
+
// expanded into one concrete path per iteration so the real files---rather than
|
|
68
|
+
// a single non-existent templated path---are recognized as pipeline outputs.
|
|
69
|
+
export function dvcStageOutputPaths(stage: DvcStage): string[] {
|
|
70
|
+
const rawPaths = (stage.outs ?? []).flatMap((out) =>
|
|
71
|
+
typeof out === "string" ? [out] : Object.keys(out),
|
|
72
|
+
);
|
|
73
|
+
const matrix = stage.matrix as Record<string, unknown[]> | undefined;
|
|
74
|
+
if (!matrix || Object.keys(matrix).length === 0) {
|
|
75
|
+
return rawPaths;
|
|
76
|
+
}
|
|
77
|
+
const items = expandDvcMatrix(matrix);
|
|
78
|
+
return rawPaths.flatMap((p) =>
|
|
79
|
+
p.includes("${item.") ? items.map((item) => applyMatrixItem(p, item)) : [p],
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// The pieces of a stage's configuration needed to attribute its DVC-reported
|
|
84
|
+
// changes to the meaningful categories shown in the sidebar (script, notebook,
|
|
85
|
+
// source, environment, declared inputs). Paths are repo-relative, matching how
|
|
86
|
+
// `calkit status` reports modified deps/outs.
|
|
87
|
+
export interface StageStaleContext {
|
|
88
|
+
scriptPath?: string;
|
|
89
|
+
notebookPath?: string;
|
|
90
|
+
targetPath?: string;
|
|
91
|
+
configuredInputs?: string[];
|
|
92
|
+
// The environment's spec/lock files (e.g. pyproject.toml + uv.lock). When any
|
|
93
|
+
// of these is a modified dep, the stage is stale because its environment
|
|
94
|
+
// changed.
|
|
95
|
+
envFilePaths?: string[];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// How a stale stage's changes map onto the categories surfaced in the tree, so
|
|
99
|
+
// the sidebar can flag exactly which inputs/outputs/script/environment are out
|
|
100
|
+
// of date rather than just marking the whole stage stale.
|
|
101
|
+
export interface StaleClassification {
|
|
102
|
+
modifiedInputs: Set<string>;
|
|
103
|
+
modifiedOutputs: Set<string>;
|
|
104
|
+
staleOutputs: Set<string>;
|
|
105
|
+
scriptStale: boolean;
|
|
106
|
+
notebookStale: boolean;
|
|
107
|
+
sourceStale: boolean;
|
|
108
|
+
envStale: boolean;
|
|
109
|
+
commandModified: boolean;
|
|
110
|
+
// Modified deps not attributable to any structured row above (e.g. an
|
|
111
|
+
// auto-added module dependency). Internal `.calkit/` bookkeeping paths are
|
|
112
|
+
// excluded since they mirror the script/notebook rows.
|
|
113
|
+
extraModifiedInputs: string[];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// calkit tracks a notebook stage's *cleaned* copy under `.calkit/` as the DVC
|
|
117
|
+
// dep, so a source-notebook edit surfaces as a change to this path rather than
|
|
118
|
+
// the notebook's own path.
|
|
119
|
+
function cleanedNotebookPath(notebookPath: string): string {
|
|
120
|
+
return `.calkit/notebooks/cleaned/${notebookPath}`;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Attribute a stale stage's modified deps/outs to the script, notebook, source,
|
|
124
|
+
// environment, and declared inputs/outputs so the sidebar can show what is
|
|
125
|
+
// stale about it. Pure (no vscode imports) so it can be unit-tested.
|
|
126
|
+
export function classifyStaleStage(
|
|
127
|
+
detail: StaleStageDetail,
|
|
128
|
+
context: StageStaleContext,
|
|
129
|
+
): StaleClassification {
|
|
130
|
+
const modifiedInputs = new Set(detail.modified_inputs ?? []);
|
|
131
|
+
const modifiedOutputs = new Set(detail.modified_outputs ?? []);
|
|
132
|
+
const staleOutputs = new Set(detail.stale_outputs ?? []);
|
|
133
|
+
const scriptStale =
|
|
134
|
+
!!context.scriptPath && modifiedInputs.has(context.scriptPath);
|
|
135
|
+
const notebookStale =
|
|
136
|
+
!!context.notebookPath &&
|
|
137
|
+
(modifiedInputs.has(context.notebookPath) ||
|
|
138
|
+
modifiedInputs.has(cleanedNotebookPath(context.notebookPath)));
|
|
139
|
+
const sourceStale =
|
|
140
|
+
!!context.targetPath && modifiedInputs.has(context.targetPath);
|
|
141
|
+
const envFilePaths = context.envFilePaths ?? [];
|
|
142
|
+
const envStale = envFilePaths.some((p) => modifiedInputs.has(p));
|
|
143
|
+
// Deps already represented by a structured row, so they aren't repeated as
|
|
144
|
+
// generic "extra" inputs.
|
|
145
|
+
const covered = new Set<string>(context.configuredInputs ?? []);
|
|
146
|
+
if (context.scriptPath) {
|
|
147
|
+
covered.add(context.scriptPath);
|
|
148
|
+
}
|
|
149
|
+
if (context.notebookPath) {
|
|
150
|
+
covered.add(context.notebookPath);
|
|
151
|
+
covered.add(cleanedNotebookPath(context.notebookPath));
|
|
152
|
+
}
|
|
153
|
+
if (context.targetPath) {
|
|
154
|
+
covered.add(context.targetPath);
|
|
155
|
+
}
|
|
156
|
+
for (const p of envFilePaths) {
|
|
157
|
+
covered.add(p);
|
|
158
|
+
}
|
|
159
|
+
const extraModifiedInputs = [...modifiedInputs].filter(
|
|
160
|
+
(p) => !covered.has(p) && !p.startsWith(".calkit/"),
|
|
161
|
+
);
|
|
162
|
+
return {
|
|
163
|
+
modifiedInputs,
|
|
164
|
+
modifiedOutputs,
|
|
165
|
+
staleOutputs,
|
|
166
|
+
scriptStale,
|
|
167
|
+
notebookStale,
|
|
168
|
+
sourceStale,
|
|
169
|
+
envStale,
|
|
170
|
+
commandModified: !!detail.modified_command,
|
|
171
|
+
extraModifiedInputs,
|
|
172
|
+
};
|
|
173
|
+
}
|