scitex-cards 0.14.0__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.
- scitex_cards-0.14.0/.djfinal.txt +14 -0
- scitex_cards-0.14.0/.djs.txt +39 -0
- scitex_cards-0.14.0/.env.example +14 -0
- scitex_cards-0.14.0/.envrc +13 -0
- scitex_cards-0.14.0/.gitattributes +2 -0
- scitex_cards-0.14.0/.githooks/_lib.sh +110 -0
- scitex_cards-0.14.0/.githooks/post-commit +37 -0
- scitex_cards-0.14.0/.githooks/pre-push +52 -0
- scitex_cards-0.14.0/.github/ci/build-in-sif.sh +69 -0
- scitex_cards-0.14.0/.github/ci/exec-in-sif.sh +51 -0
- scitex_cards-0.14.0/.github/ci/publish-in-sif.sh +109 -0
- scitex_cards-0.14.0/.github/ci/publish-with-uv.sh +93 -0
- scitex_cards-0.14.0/.github/ci/run-in-sif.sh +115 -0
- scitex_cards-0.14.0/.github/workflows/auto-merge-to-develop.yaml +124 -0
- scitex_cards-0.14.0/.github/workflows/cla.yml +34 -0
- scitex_cards-0.14.0/.github/workflows/import-smoke-on-ubuntu-py3-12.yml +21 -0
- scitex_cards-0.14.0/.github/workflows/pypi-publish-and-github-release-on-tag.yml +214 -0
- scitex_cards-0.14.0/.github/workflows/pytest-matrix-on-ubuntu-py3-11-3-12-3-13.yml +30 -0
- scitex_cards-0.14.0/.github/workflows/rtd-sphinx-build-on-ubuntu-latest.yml +58 -0
- scitex_cards-0.14.0/.github/workflows/scitex-todo-quality-audit-on-ubuntu-latest.yml +75 -0
- scitex_cards-0.14.0/.gitignore +64 -0
- scitex_cards-0.14.0/.old/20260713-column-table-removal/08-time-grouping.css +167 -0
- scitex_cards-0.14.0/.old/20260713-column-table-removal/test__sort_by_time.py +674 -0
- scitex_cards-0.14.0/.playwright-cli/page-2026-05-27T04-52-24-660Z.yml +0 -0
- scitex_cards-0.14.0/.playwright-cli/page-2026-05-27T04-52-28-336Z.yml +155 -0
- scitex_cards-0.14.0/.readthedocs.yaml +24 -0
- scitex_cards-0.14.0/.scitex/dev/cli-audit-dict.yaml +52 -0
- scitex_cards-0.14.0/.scitex/dev/config.yaml +30 -0
- scitex_cards-0.14.0/.scitex/todo/runtime/.gitkeep +0 -0
- scitex_cards-0.14.0/.scitex/todo/runtime/README.md +2 -0
- scitex_cards-0.14.0/CHANGELOG.md +2666 -0
- scitex_cards-0.14.0/CLA.md +80 -0
- scitex_cards-0.14.0/CONTRIBUTING.md +69 -0
- scitex_cards-0.14.0/LICENSE +660 -0
- scitex_cards-0.14.0/PKG-INFO +523 -0
- scitex_cards-0.14.0/README.md +463 -0
- scitex_cards-0.14.0/docs/CHEATSHEET-fleet-todo.md +425 -0
- scitex_cards-0.14.0/docs/adr/0001-universal-task-layer.md +470 -0
- scitex_cards-0.14.0/docs/adr/0002-kind-as-closed-literal-enum-and-fail-loud.md +162 -0
- scitex_cards-0.14.0/docs/adr/0003-decisions-as-first-class-graph-nodes.md +156 -0
- scitex_cards-0.14.0/docs/adr/0004-blocker-as-closed-literal-enum-orthogonal-to-kind.md +142 -0
- scitex_cards-0.14.0/docs/adr/0006-full-board-ui-spec-filterbar-columns-blocking-you.md +609 -0
- scitex_cards-0.14.0/docs/adr/0007-task-dataclass-as-single-schema-source.md +223 -0
- scitex_cards-0.14.0/docs/adr/0008-fleet-task-management.md +418 -0
- scitex_cards-0.14.0/docs/adr/0009-task-driven-feedback-four-careers.md +142 -0
- scitex_cards-0.14.0/docs/roadmap.md +65 -0
- scitex_cards-0.14.0/docs/scitex-icon-navy-inverted.png +0 -0
- scitex_cards-0.14.0/docs/scitex-logo-blue-cropped.png +0 -0
- scitex_cards-0.14.0/docs/screenshots/fb-chips-shown.png +0 -0
- scitex_cards-0.14.0/docs/screenshots/fb-overview.png +0 -0
- scitex_cards-0.14.0/docs/screenshots/p0-board-overview.png +0 -0
- scitex_cards-0.14.0/docs/screenshots/p0-business-lane.png +0 -0
- scitex_cards-0.14.0/docs/screenshots/p0-graph-view.png +0 -0
- scitex_cards-0.14.0/docs/screenshots/p0-recent-sort.png +0 -0
- scitex_cards-0.14.0/docs/screenshots/p0-table-view.png +0 -0
- scitex_cards-0.14.0/docs/screenshots/p12-business-sanity.png +0 -0
- scitex_cards-0.14.0/docs/screenshots/p12-overview.png +0 -0
- scitex_cards-0.14.0/docs/screenshots/p12-user-column.png +0 -0
- scitex_cards-0.14.0/docs/screenshots/pr105-board_v3.png +0 -0
- scitex_cards-0.14.0/docs/screenshots/pr105-legacy.png +0 -0
- scitex_cards-0.14.0/docs/screenshots/pra-default-column.png +0 -0
- scitex_cards-0.14.0/docs/screenshots/pra-graph-view.png +0 -0
- scitex_cards-0.14.0/docs/sphinx/_static/.gitkeep +0 -0
- scitex_cards-0.14.0/docs/sphinx/api/scitex_todo.rst +7 -0
- scitex_cards-0.14.0/docs/sphinx/cli_reference.rst +42 -0
- scitex_cards-0.14.0/docs/sphinx/conf.py +111 -0
- scitex_cards-0.14.0/docs/sphinx/index.rst +89 -0
- scitex_cards-0.14.0/docs/sphinx/installation.rst +49 -0
- scitex_cards-0.14.0/docs/sphinx/quickstart.rst +86 -0
- scitex_cards-0.14.0/docs/sphinx/requirements.txt +5 -0
- scitex_cards-0.14.0/examples/00_run_all.sh +12 -0
- scitex_cards-0.14.0/examples/01_render_graph.py +29 -0
- scitex_cards-0.14.0/pyproject.toml +209 -0
- scitex_cards-0.14.0/scripts/install-todo-git-hooks.sh +136 -0
- scitex_cards-0.14.0/src/scitex_cards/__init__.py +155 -0
- scitex_cards-0.14.0/src/scitex_cards/__main__.py +12 -0
- scitex_cards-0.14.0/src/scitex_cards/_adapters/__init__.py +26 -0
- scitex_cards-0.14.0/src/scitex_cards/_adapters/_in_process_pubsub.py +79 -0
- scitex_cards-0.14.0/src/scitex_cards/_adapters/_local_file_sync.py +80 -0
- scitex_cards-0.14.0/src/scitex_cards/_adapters/_null_liveness.py +30 -0
- scitex_cards-0.14.0/src/scitex_cards/_adapters/_open_acl.py +35 -0
- scitex_cards-0.14.0/src/scitex_cards/_backlog_triage.py +380 -0
- scitex_cards-0.14.0/src/scitex_cards/_channel_drain_state.py +134 -0
- scitex_cards-0.14.0/src/scitex_cards/_channel_guard.py +125 -0
- scitex_cards-0.14.0/src/scitex_cards/_channel_identity.py +120 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/__init__.py +39 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_admin.py +328 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_board.py +491 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_board_proc.py +209 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_ci_watch.py +276 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_close.py +146 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_comment.py +94 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_compat.py +297 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_completion.py +137 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_db.py +165 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_deliver.py +82 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_emit.py +205 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_gui.py +196 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_health.py +73 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_help_wait.py +105 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_hooks.py +140 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_inbox.py +201 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_index.py +151 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_introspect.py +103 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_loop.py +249 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_main.py +476 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_mcp.py +299 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_mcp_channel_verb.py +78 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_mcp_install.py +334 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_mcp_tools.py +89 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_migration_cli.py +193 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_notifyd.py +228 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_reassign.py +96 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_reconcile.py +97 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_runnable.py +226 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_skills.py +215 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_skills_propagate.py +386 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_stale.py +222 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_stats.py +369 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_sync_github.py +255 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_triage.py +106 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_update.py +240 -0
- scitex_cards-0.14.0/src/scitex_cards/_cli/_write.py +446 -0
- scitex_cards-0.14.0/src/scitex_cards/_config.py +155 -0
- scitex_cards-0.14.0/src/scitex_cards/_db.py +430 -0
- scitex_cards-0.14.0/src/scitex_cards/_db_bootstrap.py +434 -0
- scitex_cards-0.14.0/src/scitex_cards/_db_freshness.py +198 -0
- scitex_cards-0.14.0/src/scitex_cards/_db_mirror.py +291 -0
- scitex_cards-0.14.0/src/scitex_cards/_db_payload.py +98 -0
- scitex_cards-0.14.0/src/scitex_cards/_db_sections.py +141 -0
- scitex_cards-0.14.0/src/scitex_cards/_deadlines.py +384 -0
- scitex_cards-0.14.0/src/scitex_cards/_delivery/__init__.py +62 -0
- scitex_cards-0.14.0/src/scitex_cards/_delivery/_channel.py +122 -0
- scitex_cards-0.14.0/src/scitex_cards/_delivery/_channels/__init__.py +11 -0
- scitex_cards-0.14.0/src/scitex_cards/_delivery/_channels/log.py +69 -0
- scitex_cards-0.14.0/src/scitex_cards/_delivery/_channels/telegram.py +247 -0
- scitex_cards-0.14.0/src/scitex_cards/_delivery/_daemon.py +490 -0
- scitex_cards-0.14.0/src/scitex_cards/_delivery/_ledger.py +343 -0
- scitex_cards-0.14.0/src/scitex_cards/_delivery/_loop.py +239 -0
- scitex_cards-0.14.0/src/scitex_cards/_delivery/_pidfile.py +365 -0
- scitex_cards-0.14.0/src/scitex_cards/_delivery/_recipients.py +139 -0
- scitex_cards-0.14.0/src/scitex_cards/_delivery/_registry.py +157 -0
- scitex_cards-0.14.0/src/scitex_cards/_delivery/_sweeps.py +128 -0
- scitex_cards-0.14.0/src/scitex_cards/_delivery/_systemd.py +198 -0
- scitex_cards-0.14.0/src/scitex_cards/_diagram/__init__.py +27 -0
- scitex_cards-0.14.0/src/scitex_cards/_diagram/_mermaid.py +131 -0
- scitex_cards-0.14.0/src/scitex_cards/_diagram/_render.py +185 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/__init__.py +26 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/apps.py +23 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/.gitignore +3 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/eslint.config.js +16 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/index.html +14 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/package-lock.json +3166 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/package.json +27 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/public/favicon.svg +12 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/AutoRefresh.tsx +97 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/CalendarView.tsx +306 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/ChatPanel.tsx +290 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/ContextMenu.tsx +220 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/DrillHistory.tsx +66 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/EdgeKindMenu.tsx +84 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/FleetCiPills.tsx +203 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/FleetTimingPanel.tsx +463 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/GraphView.tsx +798 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/InhibitionEdge.tsx +140 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/KeyboardShortcuts.tsx +95 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/NodeDetailPanel.tsx +649 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/RecentView.tsx +287 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/SearchAutocomplete.tsx +275 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/TableView.tsx +226 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/TimelineView.tsx +405 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/Toast.tsx +50 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/TodoBoard.tsx +586 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/api/client.ts +137 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/bridge/MountPoint.ts +54 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/bridge/bridge-init.ts +23 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/calendarDate.ts +233 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/clipboard.ts +87 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/exportBoard.ts +142 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/layout.ts +735 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/persist.ts +95 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/recentSort.ts +151 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/searchQuery.ts +393 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/searchSuggest.ts +260 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/store/useBoardStore.ts +526 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/board.css +1810 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/calendar.css +312 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/chat.css +144 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/detail.css +400 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/fleet-ci-pills.css +109 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/fleet-timing.css +253 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/recent.css +233 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/search-suggest.css +80 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/table.css +41 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/timeline.css +206 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/tableFilter.ts +52 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/timelineHelpers.ts +184 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/types/board.ts +128 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/useTheme.ts +32 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/tsconfig.json +20 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/frontend/vite.config.ts +42 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/__init__.py +52 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/_comment_relay.py +134 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/chat.py +200 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/crud.py +536 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/dm.py +152 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/fleet/__init__.py +47 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/fleet/_config.py +215 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/fleet/_errors.py +42 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/fleet/ci_status_view.py +74 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/fleet/gh_ci.py +440 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/fleet/timing.py +280 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/fleet/timing_view.py +97 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/graph.py +492 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/hooks.py +105 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/nudge.py +145 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/priority.py +90 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/reopen.py +145 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/resolve.py +160 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/runnable.py +121 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/stale.py +286 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/handlers/timeline.py +359 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/management/__init__.py +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/management/commands/__init__.py +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/management/commands/scitex_cards_board.py +99 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/manifest.json +32 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/services.py +258 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/settings.py +86 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/.vite/manifest.json +11 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/assets/index.css +1 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/assets/index.js +92 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/00-theme-scrollbar-select.css +109 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/01-filterbar.css +590 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/02-card.css +494 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/03-right-and-modal.css +326 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/03b-card-actions.css +525 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/04-collapse-and-groups.css +448 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/05-responsive.css +215 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/06-layout-and-recent.css +377 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/07-toolbar-groups.css +172 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/09-timeline.css +394 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/10-agent-avatar.js +185 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/11-sticky-wall.css +256 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/11-sticky-wall.js +257 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/12-hover-tip.js +132 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/13-details-pane.css +278 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/13-timeline-hover.js +84 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/recentSort.js +199 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/searchQuery.js +447 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/searchSuggest.js +360 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/timeline.js +512 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/timelineControls.js +257 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/timelineGate.js +112 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/timelineGeo.js +92 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/timelinePack.js +97 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/timelineSelect.js +480 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/chat/chat.js +232 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/favicon.svg +12 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/index.html +15 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/templates/scitex_cards/board_v3.html +3421 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/templates/scitex_cards/chat.html +147 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/templates/scitex_cards/standalone.html +26 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/urls.py +109 -0
- scitex_cards-0.14.0/src/scitex_cards/_django/views.py +274 -0
- scitex_cards-0.14.0/src/scitex_cards/_dual_write.py +280 -0
- scitex_cards-0.14.0/src/scitex_cards/_env_compat.py +71 -0
- scitex_cards-0.14.0/src/scitex_cards/_events.py +389 -0
- scitex_cards-0.14.0/src/scitex_cards/_git_link.py +370 -0
- scitex_cards-0.14.0/src/scitex_cards/_groups.py +258 -0
- scitex_cards-0.14.0/src/scitex_cards/_health.py +380 -0
- scitex_cards-0.14.0/src/scitex_cards/_health_cards.py +270 -0
- scitex_cards-0.14.0/src/scitex_cards/_help_wait.py +170 -0
- scitex_cards-0.14.0/src/scitex_cards/_hooks/__init__.py +191 -0
- scitex_cards-0.14.0/src/scitex_cards/_hooks/_dispatch.py +116 -0
- scitex_cards-0.14.0/src/scitex_cards/_hooks/_handlers.py +226 -0
- scitex_cards-0.14.0/src/scitex_cards/_hooks/_plugins.py +324 -0
- scitex_cards-0.14.0/src/scitex_cards/_hooks/_validate.py +209 -0
- scitex_cards-0.14.0/src/scitex_cards/_idle_guard.py +187 -0
- scitex_cards-0.14.0/src/scitex_cards/_inbox.py +496 -0
- scitex_cards-0.14.0/src/scitex_cards/_inbox_maint.py +109 -0
- scitex_cards-0.14.0/src/scitex_cards/_inbox_sqlite.py +489 -0
- scitex_cards-0.14.0/src/scitex_cards/_index.py +393 -0
- scitex_cards-0.14.0/src/scitex_cards/_install_probe.py +458 -0
- scitex_cards-0.14.0/src/scitex_cards/_jobs_provider.py +205 -0
- scitex_cards-0.14.0/src/scitex_cards/_liveness.py +94 -0
- scitex_cards-0.14.0/src/scitex_cards/_mcp_app.py +69 -0
- scitex_cards-0.14.0/src/scitex_cards/_mcp_channel.py +444 -0
- scitex_cards-0.14.0/src/scitex_cards/_mcp_instructions.py +79 -0
- scitex_cards-0.14.0/src/scitex_cards/_mcp_relations.py +113 -0
- scitex_cards-0.14.0/src/scitex_cards/_mcp_server.py +317 -0
- scitex_cards-0.14.0/src/scitex_cards/_mcp_skills.py +319 -0
- scitex_cards-0.14.0/src/scitex_cards/_mcp_write.py +289 -0
- scitex_cards-0.14.0/src/scitex_cards/_migration/__init__.py +47 -0
- scitex_cards-0.14.0/src/scitex_cards/_migration/_migrate.py +686 -0
- scitex_cards-0.14.0/src/scitex_cards/_model.py +215 -0
- scitex_cards-0.14.0/src/scitex_cards/_next.py +162 -0
- scitex_cards-0.14.0/src/scitex_cards/_notify/__init__.py +98 -0
- scitex_cards-0.14.0/src/scitex_cards/_notify/_config.py +198 -0
- scitex_cards-0.14.0/src/scitex_cards/_notify/_dispatch.py +394 -0
- scitex_cards-0.14.0/src/scitex_cards/_notify/_resolver.py +380 -0
- scitex_cards-0.14.0/src/scitex_cards/_notify/_rules.py +195 -0
- scitex_cards-0.14.0/src/scitex_cards/_org.py +218 -0
- scitex_cards-0.14.0/src/scitex_cards/_owner.py +71 -0
- scitex_cards-0.14.0/src/scitex_cards/_paths.py +168 -0
- scitex_cards-0.14.0/src/scitex_cards/_ports.py +625 -0
- scitex_cards-0.14.0/src/scitex_cards/_push.py +350 -0
- scitex_cards-0.14.0/src/scitex_cards/_reconcile_prs.py +462 -0
- scitex_cards-0.14.0/src/scitex_cards/_reminder_bodies.py +140 -0
- scitex_cards-0.14.0/src/scitex_cards/_reminder_cadence.py +85 -0
- scitex_cards-0.14.0/src/scitex_cards/_reminder_enqueue.py +119 -0
- scitex_cards-0.14.0/src/scitex_cards/_reminder_liveness.py +70 -0
- scitex_cards-0.14.0/src/scitex_cards/_reminders.py +510 -0
- scitex_cards-0.14.0/src/scitex_cards/_runnable.py +403 -0
- scitex_cards-0.14.0/src/scitex_cards/_singleflight.py +124 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/manifest.yaml +54 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/01_installation.md +46 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/02_quick-start.md +51 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/03_python-api.md +85 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/04_cli-reference.md +49 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/05_mcp-tools.md +84 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/10_campaign-tracking.md +75 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/11_adopting-from-a-project.md +205 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/20_env-vars.md +39 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/21_fleet-mcp-rollout.md +182 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/22_pretooluse-hook-redirect.md +48 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/22_skills-propagation.md +140 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/30_two-tier-conventions-and-write-protocol.md +435 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/32_agent-self-consumption-loop.md +142 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/40_task-harvest.md +499 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/41_cli-mcp-gap-analysis.md +247 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/42_for-consuming-agents.md +637 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/50_board-reconciliation-runbook.md +218 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/60_pr-merge-recording-mandate.md +144 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/SKILL.md +322 -0
- scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/hooks/pre-tool-use/redirect_claude_tasklist_to_scitex_cards.sh +62 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/.buildinfo +4 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/.doctrees/__intersphinx_cache__/python_objects.inv +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/.doctrees/api/scitex_todo.doctree +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/.doctrees/cli_reference.doctree +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/.doctrees/environment.pickle +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/.doctrees/index.doctree +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/.doctrees/installation.doctree +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/.doctrees/quickstart.doctree +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_modules/index.html +144 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_modules/scitex_cards/_model.html +1354 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_modules/scitex_cards/_store.html +1107 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_sources/api/scitex_cards.rst.txt +7 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_sources/cli_reference.rst.txt +42 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_sources/index.rst.txt +89 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_sources/installation.rst.txt +49 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_sources/quickstart.rst.txt +86 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/_sphinx_javascript_frameworks_compat.js +123 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/base-stemmer.js +476 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/basic.css +906 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/check-solid.svg +4 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/clipboard.min.js +7 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/copy-button.svg +5 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/copybutton.css +94 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/copybutton.js +248 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/copybutton_funcs.js +73 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/badge_only.css +1 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/Roboto-Slab-Bold.woff +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/Roboto-Slab-Bold.woff2 +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/Roboto-Slab-Regular.woff +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/Roboto-Slab-Regular.woff2 +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/fontawesome-webfont.eot +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/fontawesome-webfont.svg +2671 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/fontawesome-webfont.ttf +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/fontawesome-webfont.woff +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/fontawesome-webfont.woff2 +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/lato-bold-italic.woff +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/lato-bold-italic.woff2 +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/lato-bold.woff +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/lato-bold.woff2 +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/lato-normal-italic.woff +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/lato-normal-italic.woff2 +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/lato-normal.woff +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/lato-normal.woff2 +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/theme.css +4 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/doctools.js +150 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/documentation_options.js +13 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/english-stemmer.js +1066 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/file.png +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-bold.eot +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-bold.ttf +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-bold.woff +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-bold.woff2 +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-bolditalic.eot +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-bolditalic.ttf +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-bolditalic.woff +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-bolditalic.woff2 +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-italic.eot +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-italic.ttf +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-italic.woff +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-italic.woff2 +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-regular.eot +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-regular.ttf +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-regular.woff +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-regular.woff2 +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/jquery.js +2 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/js/badge_only.js +1 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/js/theme.js +1 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/js/versions.js +228 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/language_data.js +13 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/minus.png +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/plus.png +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/pygments.css +75 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/searchtools.js +693 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/sphinx_highlight.js +159 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/api/scitex_cards.html +436 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/cli_reference.html +204 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/genindex.html +270 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/index.html +269 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/installation.html +204 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/objects.inv +0 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/py-modindex.html +165 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/quickstart.html +244 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/search.html +162 -0
- scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/searchindex.js +1 -0
- scitex_cards-0.14.0/src/scitex_cards/_stale_active.py +481 -0
- scitex_cards-0.14.0/src/scitex_cards/_stale_active_lines.py +146 -0
- scitex_cards-0.14.0/src/scitex_cards/_stale_active_nudge.py +533 -0
- scitex_cards-0.14.0/src/scitex_cards/_store.py +379 -0
- scitex_cards-0.14.0/src/scitex_cards/_store_comment.py +183 -0
- scitex_cards-0.14.0/src/scitex_cards/_store_enums.py +107 -0
- scitex_cards-0.14.0/src/scitex_cards/_store_events.py +151 -0
- scitex_cards-0.14.0/src/scitex_cards/_store_lifecycle.py +478 -0
- scitex_cards-0.14.0/src/scitex_cards/_store_list.py +322 -0
- scitex_cards-0.14.0/src/scitex_cards/_store_mutate.py +376 -0
- scitex_cards-0.14.0/src/scitex_cards/_store_read_sqlite.py +451 -0
- scitex_cards-0.14.0/src/scitex_cards/_store_reassign.py +161 -0
- scitex_cards-0.14.0/src/scitex_cards/_store_relations.py +233 -0
- scitex_cards-0.14.0/src/scitex_cards/_store_verify.py +149 -0
- scitex_cards-0.14.0/src/scitex_cards/_store_wip.py +188 -0
- scitex_cards-0.14.0/src/scitex_cards/_store_write.py +461 -0
- scitex_cards-0.14.0/src/scitex_cards/_task.py +440 -0
- scitex_cards-0.14.0/src/scitex_cards/_threads.py +399 -0
- scitex_cards-0.14.0/src/scitex_cards/_throughput.py +501 -0
- scitex_cards-0.14.0/src/scitex_cards/_turn_url.py +118 -0
- scitex_cards-0.14.0/src/scitex_cards/_users/__init__.py +104 -0
- scitex_cards-0.14.0/src/scitex_cards/_users/_identity.py +305 -0
- scitex_cards-0.14.0/src/scitex_cards/_users/_model.py +373 -0
- scitex_cards-0.14.0/src/scitex_cards/_users/_store.py +481 -0
- scitex_cards-0.14.0/src/scitex_cards/_validate.py +407 -0
- scitex_cards-0.14.0/src/scitex_cards/_wake_watcher.py +509 -0
- scitex_cards-0.14.0/src/scitex_cards/_yaml.py +83 -0
- scitex_cards-0.14.0/src/scitex_cards/docs/audit/2026-06-13-container-store-divergence.md +270 -0
- scitex_cards-0.14.0/src/scitex_cards/examples/.tasks.yaml.lock +0 -0
- scitex_cards-0.14.0/src/scitex_cards/examples/config.yaml +33 -0
- scitex_cards-0.14.0/src/scitex_cards/examples/tasks.yaml +299 -0
- scitex_cards-0.14.0/src/scitex_todo/__init__.py +74 -0
- scitex_cards-0.14.0/tests/examples/test_01_render_graph.py +36 -0
- scitex_cards-0.14.0/tests/integration/test_cross_package_imports.py +55 -0
- scitex_cards-0.14.0/tests/integration/test_peer_edges.py +310 -0
- scitex_cards-0.14.0/tests/scitex_cards/_adapters/__init__.py +0 -0
- scitex_cards-0.14.0/tests/scitex_cards/_adapters/test__in_process_pubsub.py +22 -0
- scitex_cards-0.14.0/tests/scitex_cards/_adapters/test__local_file_sync.py +19 -0
- scitex_cards-0.14.0/tests/scitex_cards/_adapters/test__null_liveness.py +17 -0
- scitex_cards-0.14.0/tests/scitex_cards/_adapters/test__open_acl.py +17 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__add_echo_and_blocker_none.py +189 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__blocking_operator.py +103 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__board_port_fallback.py +281 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__board_verbs.py +241 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__ci_watch.py +240 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__close.py +357 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__comment.py +129 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__completion.py +36 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__emit.py +306 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__introspect.py +78 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__loop_next.py +216 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__main.py +83 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__mcp_channel_verb.py +43 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__mcp_install_apply.py +320 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__mcp_install_fleet.py +209 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__reconcile.py +83 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__skills.py +48 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__skills_install.py +164 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__skills_propagate.py +296 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__stale.py +181 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__verb_renames.py +354 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__write.py +1053 -0
- scitex_cards-0.14.0/tests/scitex_cards/_cli/test__write_blocker_clear.py +162 -0
- scitex_cards-0.14.0/tests/scitex_cards/_delivery/__init__.py +1 -0
- scitex_cards-0.14.0/tests/scitex_cards/_delivery/_fakes.py +74 -0
- scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__channel.py +55 -0
- scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__cli_notifyd.py +105 -0
- scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__daemon.py +442 -0
- scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__ledger.py +201 -0
- scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__loop.py +281 -0
- scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__pidfile_liveness.py +270 -0
- scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__registry.py +114 -0
- scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__sweeps.py +180 -0
- scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__systemd.py +172 -0
- scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__telegram.py +205 -0
- scitex_cards-0.14.0/tests/scitex_cards/_diagram/test__mermaid.py +84 -0
- scitex_cards-0.14.0/tests/scitex_cards/_diagram/test__render.py +38 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/conftest.py +24 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/frontend/test_calendar_date.py +565 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/frontend/test_chat.py +274 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/frontend/test_chat_helpers.py +301 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/frontend/test_fleet_ci_pills.py +447 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/frontend/test_fleet_timing.py +1084 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/frontend/test_table_filter.py +312 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/frontend/test_timeline.py +254 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/frontend/test_timeline_helpers.py +423 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/fleet/__init__.py +1 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/fleet/test_ci_status_view.py +296 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/fleet/test_gh_ci.py +577 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/fleet/test_timing.py +629 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/fleet/test_timing_view.py +192 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test__chat_view.py +335 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test__dm_views.py +157 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test__hooks_views.py +191 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test__runnable_view.py +181 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test__timeline_view.py +439 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test_crud.py +533 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test_graph_cache.py +108 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test_graph_fleet.py +446 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test_graph_roles.py +117 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test_nudge.py +199 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test_priority.py +301 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test_reopen.py +298 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test_resolve.py +217 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test_stale.py +305 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/management/commands/test_scitex_cards_board.py +170 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/test__no_multiline_django_short_comments.py +82 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/test__theme_scrollbar_dropdown.py +499 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/test__toolbar_groups.py +354 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/test_apps.py +32 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/test_lane_union.py +186 -0
- scitex_cards-0.14.0/tests/scitex_cards/_django/test_views.py +444 -0
- scitex_cards-0.14.0/tests/scitex_cards/_migration/__init__.py +0 -0
- scitex_cards-0.14.0/tests/scitex_cards/_migration/test__migrate.py +268 -0
- scitex_cards-0.14.0/tests/scitex_cards/_migration/test__migrate_apply.py +235 -0
- scitex_cards-0.14.0/tests/scitex_cards/_skills/__init__.py +0 -0
- scitex_cards-0.14.0/tests/scitex_cards/_skills/test__no_hand_edit_mandate.py +53 -0
- scitex_cards-0.14.0/tests/scitex_cards/_skills/test__pr_merge_recording_mandate.py +98 -0
- scitex_cards-0.14.0/tests/scitex_cards/_skills/test__pretooluse_hook.py +116 -0
- scitex_cards-0.14.0/tests/scitex_cards/conftest.py +226 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__backlog_triage.py +206 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__blocked.py +309 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__board_v3_signatures.py +752 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__cancelled_status.py +279 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__card_message_event.py +397 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__channel_size_guard.py +220 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__completion_stamp_honesty.py +204 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__config.py +83 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__crash_safe_writer.py +343 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__db.py +595 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__deadline.py +175 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__deadline_multi_recurring.py +255 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__deadline_never_notifies.py +263 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__digest_ranked.py +82 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__dual_write.py +294 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__edge_subscribes_waiter.py +156 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__entry_points_cached.py +75 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__enum_clear.py +302 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__events.py +258 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__git_link.py +379 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__git_link_event_producers.py +342 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__group_field.py +206 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__groups.py +229 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__health.py +323 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__health_falsely_blocked.py +196 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__health_zombie_cards.py +124 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__help_wait.py +313 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__hooks.py +480 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__hooks_ordering.py +304 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__hooks_plugin_timeout.py +274 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__idle_guard.py +127 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__import_order.py +131 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__inbox.py +460 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__inbox_digest_collapse.py +191 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__inbox_sqlite.py +395 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__index.py +294 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__install_probe.py +375 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__is_overdue.py +135 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__jobs_provider.py +104 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__mcp_channel.py +544 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__mcp_channel_handshake.py +141 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__mcp_instructions.py +267 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__mcp_server.py +850 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__mcp_tools_registered.py +71 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__model.py +1397 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__next.py +266 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__notify_config.py +470 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__notify_dispatch.py +424 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__org.py +238 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__org_multi_recurring.py +115 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__owner_ssot.py +230 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__parked.py +203 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__paths.py +222 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__pending_backlog.py +187 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__ports_and_adapters.py +525 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__print_stats_single_instance.py +200 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__push.py +571 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__reassign_all.py +278 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__recent_view.js +285 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__recent_view_module.py +234 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__reconcile_prs.py +289 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__reminders.py +780 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__runnable.py +335 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__search_query.js +277 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__search_query_module.py +135 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__search_suggest.js +339 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__search_suggest_module.py +180 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__stale_active.py +213 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__stale_active_blocker_aware.py +220 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__stale_active_nudge.py +434 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__store.py +1036 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__store_assignee_liveness.py +145 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__store_card_events.py +474 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__store_concurrency.py +126 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__store_doc_preservation.py +218 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__store_git_gc.py +115 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__store_read_sqlite.py +510 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__store_verbs.py +708 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__store_verify.py +284 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__store_wip.py +260 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__threads.py +247 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__throughput.py +534 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__timeline_controls.js +142 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__timeline_gate.js +152 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__timeline_geo.js +85 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__timeline_pack.js +173 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__timeline_select.js +115 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__users.py +471 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__users_identity.py +232 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__users_write_preserves_tasks_fast.py +107 -0
- scitex_cards-0.14.0/tests/scitex_cards/test__wake_watcher.py +708 -0
- scitex_cards-0.14.0/tests/test_board_handlers_use_cached_read.py +64 -0
- scitex_cards-0.14.0/tests/test_cli_gui.py +90 -0
- scitex_cards-0.14.0/tests/test_db_mirror_incremental.py +217 -0
- scitex_cards-0.14.0/tests/test_deadline_tz_aware.py +103 -0
- scitex_cards-0.14.0/tests/test_reminder_cadence.py +109 -0
- scitex_cards-0.14.0/tests/test_scitex_cards_alias.py +38 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
........................................................................ [ 8%]
|
|
2
|
+
........................................................................ [ 17%]
|
|
3
|
+
........................................................................ [ 26%]
|
|
4
|
+
........................................................................ [ 34%]
|
|
5
|
+
........................................................................ [ 43%]
|
|
6
|
+
........................................................................ [ 52%]
|
|
7
|
+
........................................................................ [ 61%]
|
|
8
|
+
........................................................................ [ 69%]
|
|
9
|
+
........................................................................ [ 78%]
|
|
10
|
+
........................................................................ [ 87%]
|
|
11
|
+
........................................................................ [ 96%]
|
|
12
|
+
................................ [100%]
|
|
13
|
+
824 passed in 455.10s (0:07:35)
|
|
14
|
+
DONE_RC=0
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
........................................................................ [ 8%]
|
|
2
|
+
........................................................................ [ 17%]
|
|
3
|
+
........................................................................ [ 26%]
|
|
4
|
+
........................................................................ [ 34%]
|
|
5
|
+
........................................................................ [ 43%]
|
|
6
|
+
........................................................................ [ 52%]
|
|
7
|
+
.......................................................F................ [ 61%]
|
|
8
|
+
........................................................................ [ 69%]
|
|
9
|
+
........................................................................ [ 78%]
|
|
10
|
+
........................................................................ [ 87%]
|
|
11
|
+
........................................................................ [ 96%]
|
|
12
|
+
................................ [100%]
|
|
13
|
+
=================================== FAILURES ===================================
|
|
14
|
+
______________________ test_timeline_view_ungrouped_lane _______________________
|
|
15
|
+
|
|
16
|
+
store_ungrouped = PosixPath('/uvwork/tmp/pytest-of-agent/pytest-58/test_timeline_view_ungrouped_l0/tasks.yaml')
|
|
17
|
+
|
|
18
|
+
def test_timeline_view_ungrouped_lane(store_ungrouped):
|
|
19
|
+
"""A task without an agent or group lands in the ``"(ungrouped)"``
|
|
20
|
+
lane — operator-brief floor for tasks with no lane value."""
|
|
21
|
+
# Arrange
|
|
22
|
+
rf = RequestFactory()
|
|
23
|
+
req = rf.get("/timeline")
|
|
24
|
+
# Act
|
|
25
|
+
payload = json.loads(timeline_view(req).content)
|
|
26
|
+
# Assert
|
|
27
|
+
> assert payload["events"][0]["lane"] == "(ungrouped)"
|
|
28
|
+
E AssertionError: assert 'agent:test-suite' == '(ungrouped)'
|
|
29
|
+
E
|
|
30
|
+
E - (ungrouped)
|
|
31
|
+
E + agent:test-suite
|
|
32
|
+
|
|
33
|
+
tests/scitex_todo/_django/handlers/test__timeline_view.py:253: AssertionError
|
|
34
|
+
------------------------------ Captured log setup ------------------------------
|
|
35
|
+
WARNING scitex_todo._notify._dispatch:_dispatch.py:272 [scitex-todo._notify] card 't-naked' not loadable for 'created' event; skipping notify: "task id 't-naked' not found in /home/agent/.scitex/todo/tasks.yaml"
|
|
36
|
+
=========================== short test summary info ============================
|
|
37
|
+
FAILED tests/scitex_todo/_django/handlers/test__timeline_view.py::test_timeline_view_ungrouped_lane
|
|
38
|
+
1 failed, 823 passed in 392.96s (0:06:32)
|
|
39
|
+
DONE_RC=1
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# scitex-todo environment variables
|
|
2
|
+
#
|
|
3
|
+
# Copy this file to `.env` (gitignored) and edit values for your setup.
|
|
4
|
+
# CLI flags always override env vars when both are given. Variables follow
|
|
5
|
+
# the SciTeX ecosystem convention: SCITEX_<MODULE>_<NAME>.
|
|
6
|
+
#
|
|
7
|
+
# Local state (per the SciTeX local-state convention) is read from:
|
|
8
|
+
# ~/.scitex/todo/ user-global task store
|
|
9
|
+
# <proj-root>/.scitex/todo/ project-local task store (preferred)
|
|
10
|
+
|
|
11
|
+
# Absolute path to the canonical tasks.yaml task store. When set, it wins
|
|
12
|
+
# over the project/user/bundled fallback chain (but a `--tasks` CLI flag
|
|
13
|
+
# still overrides it).
|
|
14
|
+
# SCITEX_TODO_TASKS=/abs/path/to/tasks.yaml
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Load the parent directory's .envrc first (direnv), so shared
|
|
2
|
+
# repo-group env (e.g. ~/proj/.envrc) applies before these per-repo overrides.
|
|
3
|
+
source_up
|
|
4
|
+
|
|
5
|
+
# Claude Code Telegrammer
|
|
6
|
+
export CCT_ALLOWED_USERS="8379369979"
|
|
7
|
+
export CCT_AGENT_ID="scitex-todo"
|
|
8
|
+
export CCT_BOT_TOKEN="$CCT_BOT_TOKEN_TODO"
|
|
9
|
+
|
|
10
|
+
# SCITEX Todo
|
|
11
|
+
export SCITEX_TODO_AGENT_ID="scitex-todo"
|
|
12
|
+
export SCITEX_TODO_TASKS_YAML_SHARED="$HOME/.scitex/todo/tasks.yaml"
|
|
13
|
+
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Shared helpers for the scitex-todo git->card hooks (post-commit, pre-push).
|
|
4
|
+
#
|
|
5
|
+
# Phase P3 of the task-driven-feedback epic (card tcfb-p3-git-to-card).
|
|
6
|
+
# These helpers capture a local git mutation onto the matching board
|
|
7
|
+
# card's ROUTE by emitting a canonical "push" event to
|
|
8
|
+
# scitex-todo hook push --payload -
|
|
9
|
+
#
|
|
10
|
+
# SOFT linking: a card is annotated only when a card id is present in the
|
|
11
|
+
# branch name (or a `Card: <id>` commit-message trailer). Ad-hoc commits
|
|
12
|
+
# with no card id are NOT an error -- the hooks emit nothing and exit 0.
|
|
13
|
+
#
|
|
14
|
+
# BEST EFFORT: every step is guarded so a hook NEVER blocks the
|
|
15
|
+
# commit/push, even if python, the package, or the consumer is missing.
|
|
16
|
+
#
|
|
17
|
+
# This file is sourced, not executed; it defines functions only.
|
|
18
|
+
|
|
19
|
+
# Resolve a python interpreter that can import scitex_cards. Preference:
|
|
20
|
+
# 1. repo-local venv (.venv/bin/python) -- CI-parity dev setup
|
|
21
|
+
# 2. `scitex-todo` console-script's interpreter (best proxy on PATH)
|
|
22
|
+
# 3. plain python3
|
|
23
|
+
# Echoes the interpreter path; callers test importability separately.
|
|
24
|
+
sttc_python() {
|
|
25
|
+
local repo_root="$1"
|
|
26
|
+
if [ -x "${repo_root}/.venv/bin/python" ]; then
|
|
27
|
+
echo "${repo_root}/.venv/bin/python"
|
|
28
|
+
return 0
|
|
29
|
+
fi
|
|
30
|
+
if command -v python3 >/dev/null 2>&1; then
|
|
31
|
+
echo "python3"
|
|
32
|
+
return 0
|
|
33
|
+
fi
|
|
34
|
+
echo "python"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# Derive an "owner/repo" slug from the origin remote URL. Handles both
|
|
38
|
+
# SSH (git@github.com:owner/repo.git) and HTTPS
|
|
39
|
+
# (https://github.com/owner/repo.git) forms. Echoes "" if undeterminable.
|
|
40
|
+
sttc_repo_slug() {
|
|
41
|
+
local repo_root="$1"
|
|
42
|
+
local url
|
|
43
|
+
url="$(git -C "${repo_root}" remote get-url origin 2>/dev/null)" || return 0
|
|
44
|
+
[ -n "${url}" ] || return 0
|
|
45
|
+
# Strip a trailing .git, then take the last two path segments.
|
|
46
|
+
url="${url%.git}"
|
|
47
|
+
# Normalise scp-like "host:owner/repo" to ".../owner/repo".
|
|
48
|
+
url="${url/://}"
|
|
49
|
+
# Echo the trailing owner/repo (last two slash-separated segments).
|
|
50
|
+
echo "${url}" | awk -F/ '{ if (NF>=2) printf "%s/%s", $(NF-1), $NF }'
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# Emit + dispatch a push event for one commit, best-effort.
|
|
54
|
+
# Args: repo_root branch commit_sha [commit_msg_file] [trigger]
|
|
55
|
+
# - trigger (commit|push, default push) tells the consumer whether this
|
|
56
|
+
# came from post-commit (commit) or pre-push (push) so it emits the
|
|
57
|
+
# matching canonical card-event type (committed vs pushed).
|
|
58
|
+
# - Resolves the card id (branch, then Card: trailer in the msg file).
|
|
59
|
+
# - If a card id resolves, builds the event JSON in python and pipes it
|
|
60
|
+
# to `scitex-todo hook push --payload -`.
|
|
61
|
+
# - No card id -> silent exit 0 (SOFT).
|
|
62
|
+
# - Any failure -> swallowed (|| true); the hook never blocks git.
|
|
63
|
+
sttc_emit_push() {
|
|
64
|
+
local repo_root="$1" branch="$2" sha="$3" msg_file="${4:-}" trigger="${5:-push}"
|
|
65
|
+
[ -n "${branch}" ] || return 0
|
|
66
|
+
[ -n "${sha}" ] || return 0
|
|
67
|
+
|
|
68
|
+
local py slug author event
|
|
69
|
+
py="$(sttc_python "${repo_root}")"
|
|
70
|
+
|
|
71
|
+
# If the interpreter can't import scitex_cards, give up softly.
|
|
72
|
+
"${py}" -c "import scitex_cards._git_link" >/dev/null 2>&1 || return 0
|
|
73
|
+
|
|
74
|
+
slug="$(sttc_repo_slug "${repo_root}")"
|
|
75
|
+
author="$(git -C "${repo_root}" log -1 --format='%an' "${sha}" 2>/dev/null)"
|
|
76
|
+
|
|
77
|
+
local -a msg_args=()
|
|
78
|
+
if [ -n "${msg_file}" ] && [ -f "${msg_file}" ]; then
|
|
79
|
+
msg_args=(--message-file "${msg_file}")
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# Build the canonical push-event JSON in python (safe quoting of the
|
|
83
|
+
# commit message). Empty stdout == no card id == SOFT skip.
|
|
84
|
+
event="$("${py}" -m scitex_cards._git_link emit-event \
|
|
85
|
+
--repo "${slug}" \
|
|
86
|
+
--branch "${branch}" \
|
|
87
|
+
--sha "${sha}" \
|
|
88
|
+
--author "${author}" \
|
|
89
|
+
--trigger "${trigger}" \
|
|
90
|
+
"${msg_args[@]}" 2>/dev/null)" || return 0
|
|
91
|
+
[ -n "${event}" ] || return 0
|
|
92
|
+
|
|
93
|
+
# Pipe to the consumer. Prefer the repo-venv console script; fall back
|
|
94
|
+
# to `scitex-todo` on PATH, then to `python -m scitex_cards`.
|
|
95
|
+
if [ -x "${repo_root}/.venv/bin/scitex-todo" ]; then
|
|
96
|
+
printf '%s\n' "${event}" |
|
|
97
|
+
"${repo_root}/.venv/bin/scitex-todo" hook push --payload - \
|
|
98
|
+
>/dev/null 2>&1 || true
|
|
99
|
+
elif command -v scitex-todo >/dev/null 2>&1; then
|
|
100
|
+
printf '%s\n' "${event}" |
|
|
101
|
+
scitex-todo hook push --payload - >/dev/null 2>&1 || true
|
|
102
|
+
else
|
|
103
|
+
printf '%s\n' "${event}" |
|
|
104
|
+
"${py}" -m scitex_cards hook push --payload - \
|
|
105
|
+
>/dev/null 2>&1 || true
|
|
106
|
+
fi
|
|
107
|
+
return 0
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
# EOF
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# scitex-todo git->card hook: record each local commit on the matching
|
|
4
|
+
# board card's ROUTE (Phase P3, card tcfb-p3-git-to-card).
|
|
5
|
+
#
|
|
6
|
+
# SOFT linking: only fires when a card id is present in the branch name
|
|
7
|
+
# (or a `Card: <id>` commit-message trailer). Ad-hoc commits are skipped
|
|
8
|
+
# silently. BEST EFFORT: never blocks the commit -- the hook always
|
|
9
|
+
# exits 0, even on any internal failure.
|
|
10
|
+
|
|
11
|
+
set -u
|
|
12
|
+
|
|
13
|
+
HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
14
|
+
# shellcheck source=/dev/null
|
|
15
|
+
. "${HOOK_DIR}/_lib.sh" 2>/dev/null || exit 0
|
|
16
|
+
|
|
17
|
+
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || exit 0
|
|
18
|
+
[ -n "${REPO_ROOT}" ] || exit 0
|
|
19
|
+
|
|
20
|
+
BRANCH="$(git -C "${REPO_ROOT}" symbolic-ref --quiet --short HEAD 2>/dev/null)" || exit 0
|
|
21
|
+
[ -n "${BRANCH}" ] || exit 0 # detached HEAD -> nothing to link.
|
|
22
|
+
|
|
23
|
+
SHA="$(git -C "${REPO_ROOT}" rev-parse HEAD 2>/dev/null)" || exit 0
|
|
24
|
+
|
|
25
|
+
# The commit message of the just-created commit, for the `Card:` trailer
|
|
26
|
+
# fallback. Write it to a temp file so the helper reads it verbatim.
|
|
27
|
+
MSG_FILE="$(mktemp 2>/dev/null)" || MSG_FILE=""
|
|
28
|
+
if [ -n "${MSG_FILE}" ]; then
|
|
29
|
+
git -C "${REPO_ROOT}" log -1 --format='%B' HEAD >"${MSG_FILE}" 2>/dev/null || true
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
sttc_emit_push "${REPO_ROOT}" "${BRANCH}" "${SHA}" "${MSG_FILE}" "commit" || true
|
|
33
|
+
|
|
34
|
+
[ -n "${MSG_FILE}" ] && rm -f "${MSG_FILE}" 2>/dev/null
|
|
35
|
+
|
|
36
|
+
exit 0
|
|
37
|
+
# EOF
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# scitex-todo git->card hook: record pushed commits on the matching board
|
|
4
|
+
# card's ROUTE (Phase P3, card tcfb-p3-git-to-card).
|
|
5
|
+
#
|
|
6
|
+
# git invokes pre-push with `<remote-name> <remote-url>` as argv and feeds
|
|
7
|
+
# one line per pushed ref on stdin:
|
|
8
|
+
# <local_ref> SP <local_sha> SP <remote_ref> SP <remote_sha> LF
|
|
9
|
+
# For each updated branch we record its tip commit (local_sha) against the
|
|
10
|
+
# card id parsed from the branch (or a `Card:` trailer).
|
|
11
|
+
#
|
|
12
|
+
# SOFT linking: only fires when a card id is present. Ad-hoc pushes are
|
|
13
|
+
# skipped silently. BEST EFFORT: never blocks the push -- always exits 0.
|
|
14
|
+
|
|
15
|
+
set -u
|
|
16
|
+
|
|
17
|
+
HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
18
|
+
# shellcheck source=/dev/null
|
|
19
|
+
. "${HOOK_DIR}/_lib.sh" 2>/dev/null || exit 0
|
|
20
|
+
|
|
21
|
+
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || exit 0
|
|
22
|
+
[ -n "${REPO_ROOT}" ] || exit 0
|
|
23
|
+
|
|
24
|
+
# Sentinel git uses for "no such object" (deletes / fresh refs).
|
|
25
|
+
ZERO="0000000000000000000000000000000000000000"
|
|
26
|
+
|
|
27
|
+
while read -r local_ref local_sha remote_ref remote_sha; do
|
|
28
|
+
# Branch deletion (local side is the zero sha) -> nothing to record.
|
|
29
|
+
[ -n "${local_ref}" ] || continue
|
|
30
|
+
[ "${local_sha}" = "${ZERO}" ] && continue
|
|
31
|
+
[ -n "${local_sha}" ] || continue
|
|
32
|
+
|
|
33
|
+
# Only annotate branch pushes; ignore tags and other ref namespaces.
|
|
34
|
+
case "${local_ref}" in
|
|
35
|
+
refs/heads/*) branch="${local_ref#refs/heads/}" ;;
|
|
36
|
+
*) continue ;;
|
|
37
|
+
esac
|
|
38
|
+
[ -n "${branch}" ] || continue
|
|
39
|
+
|
|
40
|
+
MSG_FILE="$(mktemp 2>/dev/null)" || MSG_FILE=""
|
|
41
|
+
if [ -n "${MSG_FILE}" ]; then
|
|
42
|
+
git -C "${REPO_ROOT}" log -1 --format='%B' "${local_sha}" \
|
|
43
|
+
>"${MSG_FILE}" 2>/dev/null || true
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
sttc_emit_push "${REPO_ROOT}" "${branch}" "${local_sha}" "${MSG_FILE}" "push" || true
|
|
47
|
+
|
|
48
|
+
[ -n "${MSG_FILE}" ] && rm -f "${MSG_FILE}" 2>/dev/null
|
|
49
|
+
done
|
|
50
|
+
|
|
51
|
+
exit 0
|
|
52
|
+
# EOF
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Runs INSIDE the reused scitex-ci SIF (apptainer exec — invoked via
|
|
3
|
+
# exec-in-sif.sh). Builds scitex-todo's wheel + sdist into ./dist/.
|
|
4
|
+
#
|
|
5
|
+
# WHY build in the SIF: the self-hosted Spartan runner has no Python on the
|
|
6
|
+
# bare node (the whole reason the old `actions/setup-python@v5` step failed:
|
|
7
|
+
# "version 3.x not found for this OS"). The SIF bakes python 3.11/3.12/3.13 +
|
|
8
|
+
# pip + uv at /opt/venv-<ver>, exactly like the working pytest-matrix CI.
|
|
9
|
+
#
|
|
10
|
+
# `python -m build` needs the `build` frontend, which is NOT baked in the SIF
|
|
11
|
+
# (only scitex-dev[all,dev] deps are). Mirror run-in-sif.sh: install `build`
|
|
12
|
+
# into a writable --target on node-local /tmp and put it on PYTHONPATH. The
|
|
13
|
+
# SIF's /opt/venv-* are root-owned + RO and the compute-node HOME is RO inside
|
|
14
|
+
# the container, so a normal install fails Permission denied — a --target on
|
|
15
|
+
# writable scratch sidesteps both.
|
|
16
|
+
#
|
|
17
|
+
# Fail-loud (operator directive): a missing interpreter or a failed build is a
|
|
18
|
+
# HARD error, never a silent fallback.
|
|
19
|
+
set -euo pipefail
|
|
20
|
+
|
|
21
|
+
V="${1:-3.12}"
|
|
22
|
+
VENV="/opt/venv-$V"
|
|
23
|
+
PY="$VENV/bin/python"
|
|
24
|
+
test -x "$PY" || {
|
|
25
|
+
echo "::error::baked python missing in $VENV — rebuild the SIF: scitex-container apptainer build ci-cpu"
|
|
26
|
+
exit 1
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export LC_ALL=C.UTF-8 LANG=C.UTF-8
|
|
30
|
+
|
|
31
|
+
# Writable scratch (the runner's TMPDIR=~/.cache/tmp is a host path that does
|
|
32
|
+
# NOT resolve inside the container). Node-local /tmp is writable + ephemeral.
|
|
33
|
+
TMPDIR="/tmp/build-scitex_cards-${GITHUB_RUN_ID:-0}-${GITHUB_RUN_ATTEMPT:-0}-$V"
|
|
34
|
+
export TMPDIR
|
|
35
|
+
rm -rf "$TMPDIR"
|
|
36
|
+
mkdir -p "$TMPDIR/site" "$TMPDIR/uv-cache"
|
|
37
|
+
|
|
38
|
+
# The compute-node $HOME is RO inside the container — point every cache the
|
|
39
|
+
# installer might touch at the writable scratch (else uv/pip die creating
|
|
40
|
+
# ~/.cache).
|
|
41
|
+
export UV_CACHE_DIR="$TMPDIR/uv-cache"
|
|
42
|
+
export XDG_CACHE_HOME="$TMPDIR"
|
|
43
|
+
export PIP_CACHE_DIR="$TMPDIR/pip-cache"
|
|
44
|
+
|
|
45
|
+
# A VIRTUAL_ENV leaked from the runner profile (~/.env-3.11) is a broken
|
|
46
|
+
# symlink in here; unset it so no tool follows it.
|
|
47
|
+
unset VIRTUAL_ENV || true
|
|
48
|
+
|
|
49
|
+
export PATH="$VENV/bin:$PATH"
|
|
50
|
+
echo "build: py=$("$PY" -V) target=$TMPDIR/site"
|
|
51
|
+
|
|
52
|
+
# Install the PEP 517 build frontend into the writable target (uv fast path,
|
|
53
|
+
# pip safety net), then build with it. Clean dist/ first so only the freshly
|
|
54
|
+
# built artifacts are uploaded.
|
|
55
|
+
uv pip install --python "$PY" --target="$TMPDIR/site" build ||
|
|
56
|
+
"$PY" -m pip install --target="$TMPDIR/site" build
|
|
57
|
+
|
|
58
|
+
export PYTHONPATH="$TMPDIR/site${PYTHONPATH:+:$PYTHONPATH}"
|
|
59
|
+
|
|
60
|
+
rm -rf dist
|
|
61
|
+
"$PY" -m build --outdir dist
|
|
62
|
+
|
|
63
|
+
echo "=== built artifacts ==="
|
|
64
|
+
ls -l dist
|
|
65
|
+
# fail-loud: refuse to continue the pipeline with an empty dist/.
|
|
66
|
+
test -n "$(ls -A dist 2>/dev/null)" || {
|
|
67
|
+
echo "::error::python -m build produced no artifacts in dist/"
|
|
68
|
+
exit 1
|
|
69
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Outer apptainer-exec wrapper for scitex-tex's self-hosted (Spartan) CI.
|
|
3
|
+
#
|
|
4
|
+
# Runs ON THE RUNNER (outside the SIF). Resolves the apptainer shim + SIF image
|
|
5
|
+
# from the repo Actions Variables, then `apptainer exec`s the SIF and hands off
|
|
6
|
+
# to an INNER script (run inside the container). Keeps every workflow job's YAML
|
|
7
|
+
# down to one line — `bash .github/ci/exec-in-sif.sh <inner-script> [args...]` —
|
|
8
|
+
# and concentrates all the HPC/SIF plumbing (shim PATH, ~-expansion, scratch,
|
|
9
|
+
# binds) in one version-controlled place.
|
|
10
|
+
#
|
|
11
|
+
# Required env (set by the workflow from repo Actions Variables):
|
|
12
|
+
# SCITEX_CI_APPTAINER path to the apptainer shim (e.g. ~/.env-3.11/bin/apptainer)
|
|
13
|
+
# SCITEX_CI_SIF path to the CI SIF image (e.g. ~/.scitex/dev/containers/ci-cpu.sif)
|
|
14
|
+
#
|
|
15
|
+
# Usage:
|
|
16
|
+
# bash .github/ci/exec-in-sif.sh run-in-sif.sh 3.12
|
|
17
|
+
#
|
|
18
|
+
# Fail-loud (operator directive): a missing shim or SIF is a HARD error — never
|
|
19
|
+
# a silent fallback to a bare-runner install.
|
|
20
|
+
set -euo pipefail
|
|
21
|
+
|
|
22
|
+
INNER="${1:?inner script name required (relative to .github/ci/)}"
|
|
23
|
+
shift || true
|
|
24
|
+
|
|
25
|
+
# The runner's job shell is --noprofile --norc (no Lmod), so the apptainer shim
|
|
26
|
+
# must be put on PATH explicitly; it execs the real Apptainer binary directly.
|
|
27
|
+
# ~-expand the Actions-Variable paths: a quoted "~/…" is NOT tilde-expanded by
|
|
28
|
+
# the shell, so substitute a leading ~ with $HOME ourselves.
|
|
29
|
+
APPTAINER="${SCITEX_CI_APPTAINER:?SCITEX_CI_APPTAINER not set (repo Actions Variable)}"
|
|
30
|
+
SIF="${SCITEX_CI_SIF:?SCITEX_CI_SIF not set (repo Actions Variable)}"
|
|
31
|
+
APPTAINER="${APPTAINER/#\~/$HOME}"
|
|
32
|
+
SIF="${SIF/#\~/$HOME}"
|
|
33
|
+
export PATH="$HOME/.env-3.11/bin:$PATH"
|
|
34
|
+
|
|
35
|
+
[ -x "$APPTAINER" ] || {
|
|
36
|
+
echo "::error::apptainer shim not executable at $APPTAINER"
|
|
37
|
+
exit 1
|
|
38
|
+
}
|
|
39
|
+
[ -f "$SIF" ] || {
|
|
40
|
+
echo "::error::CI SIF missing at $SIF — rebuild it: scitex-container apptainer build ci-cpu"
|
|
41
|
+
exit 1
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# apptainer scratch on the shared FS — keeps HOME clean.
|
|
45
|
+
export APPTAINER_TMPDIR="/data/gpfs/projects/punim0264/ywatanabe/ci/apptainer-tmp"
|
|
46
|
+
mkdir -p "$APPTAINER_TMPDIR"
|
|
47
|
+
|
|
48
|
+
# --bind punim0264: $HOME/.scitex is a symlink into punim0264; bind it so the
|
|
49
|
+
# symlink resolves inside the container. --pwd "$PWD" keeps the checkout as cwd.
|
|
50
|
+
exec "$APPTAINER" exec --pwd "$PWD" --bind /data/gpfs/projects/punim0264 \
|
|
51
|
+
"$SIF" bash ".github/ci/$INNER" "$@"
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Runs INSIDE the reused scitex-ci SIF (apptainer exec — invoked via
|
|
3
|
+
# exec-in-sif.sh). Publishes ./dist/* to PyPI via MANUAL OIDC Trusted
|
|
4
|
+
# Publishing, then twine upload.
|
|
5
|
+
#
|
|
6
|
+
# WHY manual OIDC (not pypa/gh-action-pypi-publish): that action is a Docker
|
|
7
|
+
# container action. Self-hosted Spartan compute nodes have NO Docker, so the
|
|
8
|
+
# action cannot run there. PyPI Trusted Publishing is just an OIDC token
|
|
9
|
+
# exchange over plain HTTPS, so we do it by hand:
|
|
10
|
+
#
|
|
11
|
+
# 1. Ask the GitHub Actions OIDC provider for a JWT with audience=pypi,
|
|
12
|
+
# using the per-job ACTIONS_ID_TOKEN_REQUEST_{TOKEN,URL} env vars (present
|
|
13
|
+
# because the publish job declares `permissions: id-token: write`).
|
|
14
|
+
# apptainer exec (no --cleanenv) passes those host env vars into the SIF.
|
|
15
|
+
# 2. Exchange that JWT at PyPI's mint-token endpoint for a short-lived,
|
|
16
|
+
# scope-limited PyPI API token.
|
|
17
|
+
# 3. twine upload dist/* with TWINE_USERNAME=__token__ and that minted token.
|
|
18
|
+
#
|
|
19
|
+
# This requires a Trusted Publisher to be configured on PyPI for
|
|
20
|
+
# (project=scitex-todo, owner=ywatanabe1989, repo=scitex-todo,
|
|
21
|
+
# workflow=pypi-publish-and-github-release-on-tag.yml). It already is — the
|
|
22
|
+
# previous releases published via the Docker action under the same trusted
|
|
23
|
+
# publisher; only the *client* changes here, not PyPI's trust config.
|
|
24
|
+
#
|
|
25
|
+
# curl, python and (after a --target install) twine all live in the SIF.
|
|
26
|
+
#
|
|
27
|
+
# Fail-loud (operator directive): every step asserts non-empty output and
|
|
28
|
+
# `set -euo pipefail`; any failure is a HARD error with the exact cause, never
|
|
29
|
+
# a silent skip.
|
|
30
|
+
set -euo pipefail
|
|
31
|
+
|
|
32
|
+
V="${1:-3.12}"
|
|
33
|
+
VENV="/opt/venv-$V"
|
|
34
|
+
PY="$VENV/bin/python"
|
|
35
|
+
test -x "$PY" || {
|
|
36
|
+
echo "::error::baked python missing in $VENV — rebuild the SIF: scitex-container apptainer build ci-cpu"
|
|
37
|
+
exit 1
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export LC_ALL=C.UTF-8 LANG=C.UTF-8
|
|
41
|
+
|
|
42
|
+
# dist/ must already hold the artifacts (downloaded by the publish job before
|
|
43
|
+
# this script runs). Fail loud if empty.
|
|
44
|
+
if [ ! -d dist ] || [ -z "$(ls -A dist 2>/dev/null)" ]; then
|
|
45
|
+
echo "::error::dist/ is empty — nothing to publish (download the build artifact first)"
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
echo "=== dist to publish ==="
|
|
49
|
+
ls -l dist
|
|
50
|
+
|
|
51
|
+
# --- writable scratch (compute-node HOME is RO inside the container) ---
|
|
52
|
+
TMPDIR="/tmp/publish-scitex_cards-${GITHUB_RUN_ID:-0}-${GITHUB_RUN_ATTEMPT:-0}-$V"
|
|
53
|
+
export TMPDIR
|
|
54
|
+
rm -rf "$TMPDIR"
|
|
55
|
+
mkdir -p "$TMPDIR/site" "$TMPDIR/uv-cache"
|
|
56
|
+
export UV_CACHE_DIR="$TMPDIR/uv-cache"
|
|
57
|
+
export XDG_CACHE_HOME="$TMPDIR"
|
|
58
|
+
export PIP_CACHE_DIR="$TMPDIR/pip-cache"
|
|
59
|
+
unset VIRTUAL_ENV || true
|
|
60
|
+
export PATH="$VENV/bin:$PATH"
|
|
61
|
+
|
|
62
|
+
# --- step 1: request the OIDC JWT (audience=pypi) from GitHub ---
|
|
63
|
+
: "${ACTIONS_ID_TOKEN_REQUEST_TOKEN:?ACTIONS_ID_TOKEN_REQUEST_TOKEN not set — the publish job needs 'permissions: id-token: write'}"
|
|
64
|
+
: "${ACTIONS_ID_TOKEN_REQUEST_URL:?ACTIONS_ID_TOKEN_REQUEST_URL not set — the publish job needs 'permissions: id-token: write'}"
|
|
65
|
+
|
|
66
|
+
echo "=== minting OIDC JWT (audience=pypi) ==="
|
|
67
|
+
JWT="$(curl -fsS \
|
|
68
|
+
-H "Authorization: bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \
|
|
69
|
+
"${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=pypi" |
|
|
70
|
+
"$PY" -c 'import sys,json; print(json.load(sys.stdin)["value"])')"
|
|
71
|
+
test -n "$JWT" || {
|
|
72
|
+
echo "::error::OIDC JWT request returned an empty token"
|
|
73
|
+
exit 1
|
|
74
|
+
}
|
|
75
|
+
echo "OIDC JWT obtained (length=${#JWT})"
|
|
76
|
+
|
|
77
|
+
# --- step 2: exchange the JWT for a short-lived PyPI API token ---
|
|
78
|
+
echo "=== exchanging JWT at PyPI mint-token endpoint ==="
|
|
79
|
+
MINT_RESP="$(curl -sS -X POST https://pypi.org/_/oidc/mint-token \
|
|
80
|
+
-d "{\"token\":\"${JWT}\"}")"
|
|
81
|
+
MINTED="$(printf '%s' "$MINT_RESP" |
|
|
82
|
+
"$PY" -c 'import sys,json; d=json.load(sys.stdin); print(d.get("token",""))')"
|
|
83
|
+
if [ -z "$MINTED" ]; then
|
|
84
|
+
# Surface PyPI's error body VERBATIM (the JWT is NOT echoed) so a trust
|
|
85
|
+
# misconfiguration is diagnosable — this is the decisive failure mode for
|
|
86
|
+
# the fleet. Print the raw response unconditionally (most reliable on an
|
|
87
|
+
# error path); pretty-print is best-effort on top.
|
|
88
|
+
echo "::error::PyPI mint-token returned no token."
|
|
89
|
+
echo "--- PyPI mint-token response body (raw) ---"
|
|
90
|
+
printf '%s\n' "$MINT_RESP"
|
|
91
|
+
echo "--- (pretty, best-effort) ---"
|
|
92
|
+
printf '%s' "$MINT_RESP" |
|
|
93
|
+
"$PY" -c 'import sys,json; print(json.dumps(json.load(sys.stdin), indent=2))' \
|
|
94
|
+
2>/dev/null || true
|
|
95
|
+
exit 1
|
|
96
|
+
fi
|
|
97
|
+
echo "PyPI token minted (length=${#MINTED})"
|
|
98
|
+
|
|
99
|
+
# --- step 3: install twine into the writable target, then upload ---
|
|
100
|
+
echo "=== installing twine (--target) ==="
|
|
101
|
+
uv pip install --python "$PY" --target="$TMPDIR/site" twine ||
|
|
102
|
+
"$PY" -m pip install --target="$TMPDIR/site" twine
|
|
103
|
+
export PYTHONPATH="$TMPDIR/site${PYTHONPATH:+:$PYTHONPATH}"
|
|
104
|
+
|
|
105
|
+
echo "=== twine upload dist/* ==="
|
|
106
|
+
TWINE_USERNAME="__token__" TWINE_PASSWORD="$MINTED" \
|
|
107
|
+
"$PY" -m twine upload --non-interactive --disable-progress-bar dist/*
|
|
108
|
+
|
|
109
|
+
echo "PUBLISH-OK: scitex-todo dist/* uploaded to PyPI via manual OIDC trusted publishing"
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Publishes ./dist/* to PyPI via MANUAL OIDC Trusted Publishing + twine,
|
|
3
|
+
# using a uv-provisioned Python on the bare self-hosted runner.
|
|
4
|
+
#
|
|
5
|
+
# Successor to publish-in-sif.sh (2026-07-11): the shared ci-cpu.sif vanished
|
|
6
|
+
# from the Spartan runners (incident-ci-sif-vanished-release-blocked-20260711)
|
|
7
|
+
# and the SIF's original rationale — "no Python on the bare node" — is
|
|
8
|
+
# obsolete: the org-level pytest-matrix reusable workflow already provisions
|
|
9
|
+
# Python on these same runners with astral-sh/setup-uv, green for weeks.
|
|
10
|
+
# The OIDC exchange below is UNCHANGED from publish-in-sif.sh; only where
|
|
11
|
+
# Python comes from differs. PyPI's trusted-publisher config keys on
|
|
12
|
+
# (owner, repo, workflow file name), none of which change here.
|
|
13
|
+
#
|
|
14
|
+
# WHY manual OIDC (not pypa/gh-action-pypi-publish): that action is a Docker
|
|
15
|
+
# container action and the Spartan compute nodes have no Docker. Trusted
|
|
16
|
+
# Publishing is just an OIDC token exchange over HTTPS:
|
|
17
|
+
# 1. JWT (audience=pypi) from the Actions OIDC provider, via the per-job
|
|
18
|
+
# ACTIONS_ID_TOKEN_REQUEST_{TOKEN,URL} env vars (present because the
|
|
19
|
+
# publish job declares `permissions: id-token: write`).
|
|
20
|
+
# 2. Exchange the JWT at PyPI's mint-token endpoint for a short-lived token.
|
|
21
|
+
# 3. twine upload dist/* with TWINE_USERNAME=__token__.
|
|
22
|
+
#
|
|
23
|
+
# Fail-loud (operator directive): set -euo pipefail; every step asserts
|
|
24
|
+
# non-empty output; failures carry the exact cause, never a silent skip.
|
|
25
|
+
set -euo pipefail
|
|
26
|
+
|
|
27
|
+
command -v uv >/dev/null || {
|
|
28
|
+
echo "::error::uv not on PATH — the workflow must run astral-sh/setup-uv before this script"
|
|
29
|
+
exit 1
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# Provision the interpreter (downloads a standalone CPython if the runner has
|
|
33
|
+
# none — the whole point of retiring the SIF).
|
|
34
|
+
uv venv --python 3.12 .venv-publish
|
|
35
|
+
PY=".venv-publish/bin/python"
|
|
36
|
+
test -x "$PY" || {
|
|
37
|
+
echo "::error::uv venv did not produce $PY"
|
|
38
|
+
exit 1
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export LC_ALL=C.UTF-8 LANG=C.UTF-8
|
|
42
|
+
|
|
43
|
+
if [ ! -d dist ] || [ -z "$(ls -A dist 2>/dev/null)" ]; then
|
|
44
|
+
echo "::error::dist/ is empty — nothing to publish (download the build artifact first)"
|
|
45
|
+
exit 1
|
|
46
|
+
fi
|
|
47
|
+
echo "=== dist to publish ==="
|
|
48
|
+
ls -la dist/
|
|
49
|
+
|
|
50
|
+
# --- step 1: request the OIDC JWT (audience=pypi) from GitHub ---
|
|
51
|
+
: "${ACTIONS_ID_TOKEN_REQUEST_TOKEN:?not set — the publish job needs 'permissions: id-token: write'}"
|
|
52
|
+
: "${ACTIONS_ID_TOKEN_REQUEST_URL:?not set — the publish job needs 'permissions: id-token: write'}"
|
|
53
|
+
|
|
54
|
+
echo "=== minting OIDC JWT (audience=pypi) ==="
|
|
55
|
+
JWT="$(curl -fsS \
|
|
56
|
+
-H "Authorization: bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \
|
|
57
|
+
"${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=pypi" |
|
|
58
|
+
"$PY" -c 'import sys,json; print(json.load(sys.stdin)["value"])')"
|
|
59
|
+
test -n "$JWT" || {
|
|
60
|
+
echo "::error::OIDC JWT request returned an empty token"
|
|
61
|
+
exit 1
|
|
62
|
+
}
|
|
63
|
+
echo "OIDC JWT obtained (length=${#JWT})"
|
|
64
|
+
|
|
65
|
+
# --- step 2: exchange the JWT for a short-lived PyPI API token ---
|
|
66
|
+
echo "=== exchanging JWT at PyPI mint-token endpoint ==="
|
|
67
|
+
MINT_RESP="$(curl -sS -X POST https://pypi.org/_/oidc/mint-token \
|
|
68
|
+
-d "{\"token\":\"${JWT}\"}")"
|
|
69
|
+
MINTED="$(printf '%s' "$MINT_RESP" |
|
|
70
|
+
"$PY" -c 'import sys,json; d=json.load(sys.stdin); print(d.get("token",""))')"
|
|
71
|
+
if [ -z "$MINTED" ]; then
|
|
72
|
+
# Surface PyPI's error body VERBATIM (the JWT is NOT echoed) so a trust
|
|
73
|
+
# misconfiguration is diagnosable.
|
|
74
|
+
echo "::error::PyPI mint-token returned no token."
|
|
75
|
+
echo "--- PyPI mint-token response body (raw) ---"
|
|
76
|
+
printf '%s\n' "$MINT_RESP"
|
|
77
|
+
echo "--- (pretty, best-effort) ---"
|
|
78
|
+
printf '%s' "$MINT_RESP" |
|
|
79
|
+
"$PY" -c 'import sys,json; print(json.dumps(json.load(sys.stdin), indent=2))' \
|
|
80
|
+
2>/dev/null || true
|
|
81
|
+
exit 1
|
|
82
|
+
fi
|
|
83
|
+
echo "PyPI token minted (length=${#MINTED})"
|
|
84
|
+
|
|
85
|
+
# --- step 3: twine upload ---
|
|
86
|
+
echo "=== installing twine into the publish venv ==="
|
|
87
|
+
uv pip install --python "$PY" twine
|
|
88
|
+
|
|
89
|
+
echo "=== twine upload dist/* ==="
|
|
90
|
+
TWINE_USERNAME="__token__" TWINE_PASSWORD="$MINTED" \
|
|
91
|
+
"$PY" -m twine upload --non-interactive --disable-progress-bar dist/*
|
|
92
|
+
|
|
93
|
+
echo "PUBLISH-OK: dist/* uploaded to PyPI via manual OIDC trusted publishing (uv-provisioned python)"
|