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.
Files changed (644) hide show
  1. scitex_cards-0.14.0/.djfinal.txt +14 -0
  2. scitex_cards-0.14.0/.djs.txt +39 -0
  3. scitex_cards-0.14.0/.env.example +14 -0
  4. scitex_cards-0.14.0/.envrc +13 -0
  5. scitex_cards-0.14.0/.gitattributes +2 -0
  6. scitex_cards-0.14.0/.githooks/_lib.sh +110 -0
  7. scitex_cards-0.14.0/.githooks/post-commit +37 -0
  8. scitex_cards-0.14.0/.githooks/pre-push +52 -0
  9. scitex_cards-0.14.0/.github/ci/build-in-sif.sh +69 -0
  10. scitex_cards-0.14.0/.github/ci/exec-in-sif.sh +51 -0
  11. scitex_cards-0.14.0/.github/ci/publish-in-sif.sh +109 -0
  12. scitex_cards-0.14.0/.github/ci/publish-with-uv.sh +93 -0
  13. scitex_cards-0.14.0/.github/ci/run-in-sif.sh +115 -0
  14. scitex_cards-0.14.0/.github/workflows/auto-merge-to-develop.yaml +124 -0
  15. scitex_cards-0.14.0/.github/workflows/cla.yml +34 -0
  16. scitex_cards-0.14.0/.github/workflows/import-smoke-on-ubuntu-py3-12.yml +21 -0
  17. scitex_cards-0.14.0/.github/workflows/pypi-publish-and-github-release-on-tag.yml +214 -0
  18. scitex_cards-0.14.0/.github/workflows/pytest-matrix-on-ubuntu-py3-11-3-12-3-13.yml +30 -0
  19. scitex_cards-0.14.0/.github/workflows/rtd-sphinx-build-on-ubuntu-latest.yml +58 -0
  20. scitex_cards-0.14.0/.github/workflows/scitex-todo-quality-audit-on-ubuntu-latest.yml +75 -0
  21. scitex_cards-0.14.0/.gitignore +64 -0
  22. scitex_cards-0.14.0/.old/20260713-column-table-removal/08-time-grouping.css +167 -0
  23. scitex_cards-0.14.0/.old/20260713-column-table-removal/test__sort_by_time.py +674 -0
  24. scitex_cards-0.14.0/.playwright-cli/page-2026-05-27T04-52-24-660Z.yml +0 -0
  25. scitex_cards-0.14.0/.playwright-cli/page-2026-05-27T04-52-28-336Z.yml +155 -0
  26. scitex_cards-0.14.0/.readthedocs.yaml +24 -0
  27. scitex_cards-0.14.0/.scitex/dev/cli-audit-dict.yaml +52 -0
  28. scitex_cards-0.14.0/.scitex/dev/config.yaml +30 -0
  29. scitex_cards-0.14.0/.scitex/todo/runtime/.gitkeep +0 -0
  30. scitex_cards-0.14.0/.scitex/todo/runtime/README.md +2 -0
  31. scitex_cards-0.14.0/CHANGELOG.md +2666 -0
  32. scitex_cards-0.14.0/CLA.md +80 -0
  33. scitex_cards-0.14.0/CONTRIBUTING.md +69 -0
  34. scitex_cards-0.14.0/LICENSE +660 -0
  35. scitex_cards-0.14.0/PKG-INFO +523 -0
  36. scitex_cards-0.14.0/README.md +463 -0
  37. scitex_cards-0.14.0/docs/CHEATSHEET-fleet-todo.md +425 -0
  38. scitex_cards-0.14.0/docs/adr/0001-universal-task-layer.md +470 -0
  39. scitex_cards-0.14.0/docs/adr/0002-kind-as-closed-literal-enum-and-fail-loud.md +162 -0
  40. scitex_cards-0.14.0/docs/adr/0003-decisions-as-first-class-graph-nodes.md +156 -0
  41. scitex_cards-0.14.0/docs/adr/0004-blocker-as-closed-literal-enum-orthogonal-to-kind.md +142 -0
  42. scitex_cards-0.14.0/docs/adr/0006-full-board-ui-spec-filterbar-columns-blocking-you.md +609 -0
  43. scitex_cards-0.14.0/docs/adr/0007-task-dataclass-as-single-schema-source.md +223 -0
  44. scitex_cards-0.14.0/docs/adr/0008-fleet-task-management.md +418 -0
  45. scitex_cards-0.14.0/docs/adr/0009-task-driven-feedback-four-careers.md +142 -0
  46. scitex_cards-0.14.0/docs/roadmap.md +65 -0
  47. scitex_cards-0.14.0/docs/scitex-icon-navy-inverted.png +0 -0
  48. scitex_cards-0.14.0/docs/scitex-logo-blue-cropped.png +0 -0
  49. scitex_cards-0.14.0/docs/screenshots/fb-chips-shown.png +0 -0
  50. scitex_cards-0.14.0/docs/screenshots/fb-overview.png +0 -0
  51. scitex_cards-0.14.0/docs/screenshots/p0-board-overview.png +0 -0
  52. scitex_cards-0.14.0/docs/screenshots/p0-business-lane.png +0 -0
  53. scitex_cards-0.14.0/docs/screenshots/p0-graph-view.png +0 -0
  54. scitex_cards-0.14.0/docs/screenshots/p0-recent-sort.png +0 -0
  55. scitex_cards-0.14.0/docs/screenshots/p0-table-view.png +0 -0
  56. scitex_cards-0.14.0/docs/screenshots/p12-business-sanity.png +0 -0
  57. scitex_cards-0.14.0/docs/screenshots/p12-overview.png +0 -0
  58. scitex_cards-0.14.0/docs/screenshots/p12-user-column.png +0 -0
  59. scitex_cards-0.14.0/docs/screenshots/pr105-board_v3.png +0 -0
  60. scitex_cards-0.14.0/docs/screenshots/pr105-legacy.png +0 -0
  61. scitex_cards-0.14.0/docs/screenshots/pra-default-column.png +0 -0
  62. scitex_cards-0.14.0/docs/screenshots/pra-graph-view.png +0 -0
  63. scitex_cards-0.14.0/docs/sphinx/_static/.gitkeep +0 -0
  64. scitex_cards-0.14.0/docs/sphinx/api/scitex_todo.rst +7 -0
  65. scitex_cards-0.14.0/docs/sphinx/cli_reference.rst +42 -0
  66. scitex_cards-0.14.0/docs/sphinx/conf.py +111 -0
  67. scitex_cards-0.14.0/docs/sphinx/index.rst +89 -0
  68. scitex_cards-0.14.0/docs/sphinx/installation.rst +49 -0
  69. scitex_cards-0.14.0/docs/sphinx/quickstart.rst +86 -0
  70. scitex_cards-0.14.0/docs/sphinx/requirements.txt +5 -0
  71. scitex_cards-0.14.0/examples/00_run_all.sh +12 -0
  72. scitex_cards-0.14.0/examples/01_render_graph.py +29 -0
  73. scitex_cards-0.14.0/pyproject.toml +209 -0
  74. scitex_cards-0.14.0/scripts/install-todo-git-hooks.sh +136 -0
  75. scitex_cards-0.14.0/src/scitex_cards/__init__.py +155 -0
  76. scitex_cards-0.14.0/src/scitex_cards/__main__.py +12 -0
  77. scitex_cards-0.14.0/src/scitex_cards/_adapters/__init__.py +26 -0
  78. scitex_cards-0.14.0/src/scitex_cards/_adapters/_in_process_pubsub.py +79 -0
  79. scitex_cards-0.14.0/src/scitex_cards/_adapters/_local_file_sync.py +80 -0
  80. scitex_cards-0.14.0/src/scitex_cards/_adapters/_null_liveness.py +30 -0
  81. scitex_cards-0.14.0/src/scitex_cards/_adapters/_open_acl.py +35 -0
  82. scitex_cards-0.14.0/src/scitex_cards/_backlog_triage.py +380 -0
  83. scitex_cards-0.14.0/src/scitex_cards/_channel_drain_state.py +134 -0
  84. scitex_cards-0.14.0/src/scitex_cards/_channel_guard.py +125 -0
  85. scitex_cards-0.14.0/src/scitex_cards/_channel_identity.py +120 -0
  86. scitex_cards-0.14.0/src/scitex_cards/_cli/__init__.py +39 -0
  87. scitex_cards-0.14.0/src/scitex_cards/_cli/_admin.py +328 -0
  88. scitex_cards-0.14.0/src/scitex_cards/_cli/_board.py +491 -0
  89. scitex_cards-0.14.0/src/scitex_cards/_cli/_board_proc.py +209 -0
  90. scitex_cards-0.14.0/src/scitex_cards/_cli/_ci_watch.py +276 -0
  91. scitex_cards-0.14.0/src/scitex_cards/_cli/_close.py +146 -0
  92. scitex_cards-0.14.0/src/scitex_cards/_cli/_comment.py +94 -0
  93. scitex_cards-0.14.0/src/scitex_cards/_cli/_compat.py +297 -0
  94. scitex_cards-0.14.0/src/scitex_cards/_cli/_completion.py +137 -0
  95. scitex_cards-0.14.0/src/scitex_cards/_cli/_db.py +165 -0
  96. scitex_cards-0.14.0/src/scitex_cards/_cli/_deliver.py +82 -0
  97. scitex_cards-0.14.0/src/scitex_cards/_cli/_emit.py +205 -0
  98. scitex_cards-0.14.0/src/scitex_cards/_cli/_gui.py +196 -0
  99. scitex_cards-0.14.0/src/scitex_cards/_cli/_health.py +73 -0
  100. scitex_cards-0.14.0/src/scitex_cards/_cli/_help_wait.py +105 -0
  101. scitex_cards-0.14.0/src/scitex_cards/_cli/_hooks.py +140 -0
  102. scitex_cards-0.14.0/src/scitex_cards/_cli/_inbox.py +201 -0
  103. scitex_cards-0.14.0/src/scitex_cards/_cli/_index.py +151 -0
  104. scitex_cards-0.14.0/src/scitex_cards/_cli/_introspect.py +103 -0
  105. scitex_cards-0.14.0/src/scitex_cards/_cli/_loop.py +249 -0
  106. scitex_cards-0.14.0/src/scitex_cards/_cli/_main.py +476 -0
  107. scitex_cards-0.14.0/src/scitex_cards/_cli/_mcp.py +299 -0
  108. scitex_cards-0.14.0/src/scitex_cards/_cli/_mcp_channel_verb.py +78 -0
  109. scitex_cards-0.14.0/src/scitex_cards/_cli/_mcp_install.py +334 -0
  110. scitex_cards-0.14.0/src/scitex_cards/_cli/_mcp_tools.py +89 -0
  111. scitex_cards-0.14.0/src/scitex_cards/_cli/_migration_cli.py +193 -0
  112. scitex_cards-0.14.0/src/scitex_cards/_cli/_notifyd.py +228 -0
  113. scitex_cards-0.14.0/src/scitex_cards/_cli/_reassign.py +96 -0
  114. scitex_cards-0.14.0/src/scitex_cards/_cli/_reconcile.py +97 -0
  115. scitex_cards-0.14.0/src/scitex_cards/_cli/_runnable.py +226 -0
  116. scitex_cards-0.14.0/src/scitex_cards/_cli/_skills.py +215 -0
  117. scitex_cards-0.14.0/src/scitex_cards/_cli/_skills_propagate.py +386 -0
  118. scitex_cards-0.14.0/src/scitex_cards/_cli/_stale.py +222 -0
  119. scitex_cards-0.14.0/src/scitex_cards/_cli/_stats.py +369 -0
  120. scitex_cards-0.14.0/src/scitex_cards/_cli/_sync_github.py +255 -0
  121. scitex_cards-0.14.0/src/scitex_cards/_cli/_triage.py +106 -0
  122. scitex_cards-0.14.0/src/scitex_cards/_cli/_update.py +240 -0
  123. scitex_cards-0.14.0/src/scitex_cards/_cli/_write.py +446 -0
  124. scitex_cards-0.14.0/src/scitex_cards/_config.py +155 -0
  125. scitex_cards-0.14.0/src/scitex_cards/_db.py +430 -0
  126. scitex_cards-0.14.0/src/scitex_cards/_db_bootstrap.py +434 -0
  127. scitex_cards-0.14.0/src/scitex_cards/_db_freshness.py +198 -0
  128. scitex_cards-0.14.0/src/scitex_cards/_db_mirror.py +291 -0
  129. scitex_cards-0.14.0/src/scitex_cards/_db_payload.py +98 -0
  130. scitex_cards-0.14.0/src/scitex_cards/_db_sections.py +141 -0
  131. scitex_cards-0.14.0/src/scitex_cards/_deadlines.py +384 -0
  132. scitex_cards-0.14.0/src/scitex_cards/_delivery/__init__.py +62 -0
  133. scitex_cards-0.14.0/src/scitex_cards/_delivery/_channel.py +122 -0
  134. scitex_cards-0.14.0/src/scitex_cards/_delivery/_channels/__init__.py +11 -0
  135. scitex_cards-0.14.0/src/scitex_cards/_delivery/_channels/log.py +69 -0
  136. scitex_cards-0.14.0/src/scitex_cards/_delivery/_channels/telegram.py +247 -0
  137. scitex_cards-0.14.0/src/scitex_cards/_delivery/_daemon.py +490 -0
  138. scitex_cards-0.14.0/src/scitex_cards/_delivery/_ledger.py +343 -0
  139. scitex_cards-0.14.0/src/scitex_cards/_delivery/_loop.py +239 -0
  140. scitex_cards-0.14.0/src/scitex_cards/_delivery/_pidfile.py +365 -0
  141. scitex_cards-0.14.0/src/scitex_cards/_delivery/_recipients.py +139 -0
  142. scitex_cards-0.14.0/src/scitex_cards/_delivery/_registry.py +157 -0
  143. scitex_cards-0.14.0/src/scitex_cards/_delivery/_sweeps.py +128 -0
  144. scitex_cards-0.14.0/src/scitex_cards/_delivery/_systemd.py +198 -0
  145. scitex_cards-0.14.0/src/scitex_cards/_diagram/__init__.py +27 -0
  146. scitex_cards-0.14.0/src/scitex_cards/_diagram/_mermaid.py +131 -0
  147. scitex_cards-0.14.0/src/scitex_cards/_diagram/_render.py +185 -0
  148. scitex_cards-0.14.0/src/scitex_cards/_django/__init__.py +26 -0
  149. scitex_cards-0.14.0/src/scitex_cards/_django/apps.py +23 -0
  150. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/.gitignore +3 -0
  151. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/eslint.config.js +16 -0
  152. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/index.html +14 -0
  153. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/package-lock.json +3166 -0
  154. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/package.json +27 -0
  155. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/public/favicon.svg +12 -0
  156. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/AutoRefresh.tsx +97 -0
  157. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/CalendarView.tsx +306 -0
  158. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/ChatPanel.tsx +290 -0
  159. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/ContextMenu.tsx +220 -0
  160. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/DrillHistory.tsx +66 -0
  161. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/EdgeKindMenu.tsx +84 -0
  162. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/FleetCiPills.tsx +203 -0
  163. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/FleetTimingPanel.tsx +463 -0
  164. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/GraphView.tsx +798 -0
  165. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/InhibitionEdge.tsx +140 -0
  166. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/KeyboardShortcuts.tsx +95 -0
  167. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/NodeDetailPanel.tsx +649 -0
  168. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/RecentView.tsx +287 -0
  169. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/SearchAutocomplete.tsx +275 -0
  170. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/TableView.tsx +226 -0
  171. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/TimelineView.tsx +405 -0
  172. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/Toast.tsx +50 -0
  173. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/TodoBoard.tsx +586 -0
  174. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/api/client.ts +137 -0
  175. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/bridge/MountPoint.ts +54 -0
  176. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/bridge/bridge-init.ts +23 -0
  177. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/calendarDate.ts +233 -0
  178. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/clipboard.ts +87 -0
  179. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/exportBoard.ts +142 -0
  180. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/layout.ts +735 -0
  181. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/persist.ts +95 -0
  182. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/recentSort.ts +151 -0
  183. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/searchQuery.ts +393 -0
  184. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/searchSuggest.ts +260 -0
  185. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/store/useBoardStore.ts +526 -0
  186. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/board.css +1810 -0
  187. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/calendar.css +312 -0
  188. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/chat.css +144 -0
  189. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/detail.css +400 -0
  190. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/fleet-ci-pills.css +109 -0
  191. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/fleet-timing.css +253 -0
  192. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/recent.css +233 -0
  193. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/search-suggest.css +80 -0
  194. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/table.css +41 -0
  195. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/styles/timeline.css +206 -0
  196. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/tableFilter.ts +52 -0
  197. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/timelineHelpers.ts +184 -0
  198. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/types/board.ts +128 -0
  199. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/src/useTheme.ts +32 -0
  200. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/tsconfig.json +20 -0
  201. scitex_cards-0.14.0/src/scitex_cards/_django/frontend/vite.config.ts +42 -0
  202. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/__init__.py +52 -0
  203. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/_comment_relay.py +134 -0
  204. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/chat.py +200 -0
  205. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/crud.py +536 -0
  206. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/dm.py +152 -0
  207. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/fleet/__init__.py +47 -0
  208. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/fleet/_config.py +215 -0
  209. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/fleet/_errors.py +42 -0
  210. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/fleet/ci_status_view.py +74 -0
  211. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/fleet/gh_ci.py +440 -0
  212. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/fleet/timing.py +280 -0
  213. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/fleet/timing_view.py +97 -0
  214. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/graph.py +492 -0
  215. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/hooks.py +105 -0
  216. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/nudge.py +145 -0
  217. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/priority.py +90 -0
  218. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/reopen.py +145 -0
  219. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/resolve.py +160 -0
  220. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/runnable.py +121 -0
  221. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/stale.py +286 -0
  222. scitex_cards-0.14.0/src/scitex_cards/_django/handlers/timeline.py +359 -0
  223. scitex_cards-0.14.0/src/scitex_cards/_django/management/__init__.py +0 -0
  224. scitex_cards-0.14.0/src/scitex_cards/_django/management/commands/__init__.py +0 -0
  225. scitex_cards-0.14.0/src/scitex_cards/_django/management/commands/scitex_cards_board.py +99 -0
  226. scitex_cards-0.14.0/src/scitex_cards/_django/manifest.json +32 -0
  227. scitex_cards-0.14.0/src/scitex_cards/_django/services.py +258 -0
  228. scitex_cards-0.14.0/src/scitex_cards/_django/settings.py +86 -0
  229. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/.vite/manifest.json +11 -0
  230. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/assets/index.css +1 -0
  231. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/assets/index.js +92 -0
  232. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/00-theme-scrollbar-select.css +109 -0
  233. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/01-filterbar.css +590 -0
  234. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/02-card.css +494 -0
  235. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/03-right-and-modal.css +326 -0
  236. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/03b-card-actions.css +525 -0
  237. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/04-collapse-and-groups.css +448 -0
  238. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/05-responsive.css +215 -0
  239. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/06-layout-and-recent.css +377 -0
  240. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/07-toolbar-groups.css +172 -0
  241. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/09-timeline.css +394 -0
  242. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/10-agent-avatar.js +185 -0
  243. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/11-sticky-wall.css +256 -0
  244. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/11-sticky-wall.js +257 -0
  245. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/12-hover-tip.js +132 -0
  246. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/13-details-pane.css +278 -0
  247. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/13-timeline-hover.js +84 -0
  248. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/recentSort.js +199 -0
  249. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/searchQuery.js +447 -0
  250. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/searchSuggest.js +360 -0
  251. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/timeline.js +512 -0
  252. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/timelineControls.js +257 -0
  253. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/timelineGate.js +112 -0
  254. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/timelineGeo.js +92 -0
  255. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/timelinePack.js +97 -0
  256. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/board_v3/timelineSelect.js +480 -0
  257. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/chat/chat.js +232 -0
  258. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/favicon.svg +12 -0
  259. scitex_cards-0.14.0/src/scitex_cards/_django/static/scitex_cards/index.html +15 -0
  260. scitex_cards-0.14.0/src/scitex_cards/_django/templates/scitex_cards/board_v3.html +3421 -0
  261. scitex_cards-0.14.0/src/scitex_cards/_django/templates/scitex_cards/chat.html +147 -0
  262. scitex_cards-0.14.0/src/scitex_cards/_django/templates/scitex_cards/standalone.html +26 -0
  263. scitex_cards-0.14.0/src/scitex_cards/_django/urls.py +109 -0
  264. scitex_cards-0.14.0/src/scitex_cards/_django/views.py +274 -0
  265. scitex_cards-0.14.0/src/scitex_cards/_dual_write.py +280 -0
  266. scitex_cards-0.14.0/src/scitex_cards/_env_compat.py +71 -0
  267. scitex_cards-0.14.0/src/scitex_cards/_events.py +389 -0
  268. scitex_cards-0.14.0/src/scitex_cards/_git_link.py +370 -0
  269. scitex_cards-0.14.0/src/scitex_cards/_groups.py +258 -0
  270. scitex_cards-0.14.0/src/scitex_cards/_health.py +380 -0
  271. scitex_cards-0.14.0/src/scitex_cards/_health_cards.py +270 -0
  272. scitex_cards-0.14.0/src/scitex_cards/_help_wait.py +170 -0
  273. scitex_cards-0.14.0/src/scitex_cards/_hooks/__init__.py +191 -0
  274. scitex_cards-0.14.0/src/scitex_cards/_hooks/_dispatch.py +116 -0
  275. scitex_cards-0.14.0/src/scitex_cards/_hooks/_handlers.py +226 -0
  276. scitex_cards-0.14.0/src/scitex_cards/_hooks/_plugins.py +324 -0
  277. scitex_cards-0.14.0/src/scitex_cards/_hooks/_validate.py +209 -0
  278. scitex_cards-0.14.0/src/scitex_cards/_idle_guard.py +187 -0
  279. scitex_cards-0.14.0/src/scitex_cards/_inbox.py +496 -0
  280. scitex_cards-0.14.0/src/scitex_cards/_inbox_maint.py +109 -0
  281. scitex_cards-0.14.0/src/scitex_cards/_inbox_sqlite.py +489 -0
  282. scitex_cards-0.14.0/src/scitex_cards/_index.py +393 -0
  283. scitex_cards-0.14.0/src/scitex_cards/_install_probe.py +458 -0
  284. scitex_cards-0.14.0/src/scitex_cards/_jobs_provider.py +205 -0
  285. scitex_cards-0.14.0/src/scitex_cards/_liveness.py +94 -0
  286. scitex_cards-0.14.0/src/scitex_cards/_mcp_app.py +69 -0
  287. scitex_cards-0.14.0/src/scitex_cards/_mcp_channel.py +444 -0
  288. scitex_cards-0.14.0/src/scitex_cards/_mcp_instructions.py +79 -0
  289. scitex_cards-0.14.0/src/scitex_cards/_mcp_relations.py +113 -0
  290. scitex_cards-0.14.0/src/scitex_cards/_mcp_server.py +317 -0
  291. scitex_cards-0.14.0/src/scitex_cards/_mcp_skills.py +319 -0
  292. scitex_cards-0.14.0/src/scitex_cards/_mcp_write.py +289 -0
  293. scitex_cards-0.14.0/src/scitex_cards/_migration/__init__.py +47 -0
  294. scitex_cards-0.14.0/src/scitex_cards/_migration/_migrate.py +686 -0
  295. scitex_cards-0.14.0/src/scitex_cards/_model.py +215 -0
  296. scitex_cards-0.14.0/src/scitex_cards/_next.py +162 -0
  297. scitex_cards-0.14.0/src/scitex_cards/_notify/__init__.py +98 -0
  298. scitex_cards-0.14.0/src/scitex_cards/_notify/_config.py +198 -0
  299. scitex_cards-0.14.0/src/scitex_cards/_notify/_dispatch.py +394 -0
  300. scitex_cards-0.14.0/src/scitex_cards/_notify/_resolver.py +380 -0
  301. scitex_cards-0.14.0/src/scitex_cards/_notify/_rules.py +195 -0
  302. scitex_cards-0.14.0/src/scitex_cards/_org.py +218 -0
  303. scitex_cards-0.14.0/src/scitex_cards/_owner.py +71 -0
  304. scitex_cards-0.14.0/src/scitex_cards/_paths.py +168 -0
  305. scitex_cards-0.14.0/src/scitex_cards/_ports.py +625 -0
  306. scitex_cards-0.14.0/src/scitex_cards/_push.py +350 -0
  307. scitex_cards-0.14.0/src/scitex_cards/_reconcile_prs.py +462 -0
  308. scitex_cards-0.14.0/src/scitex_cards/_reminder_bodies.py +140 -0
  309. scitex_cards-0.14.0/src/scitex_cards/_reminder_cadence.py +85 -0
  310. scitex_cards-0.14.0/src/scitex_cards/_reminder_enqueue.py +119 -0
  311. scitex_cards-0.14.0/src/scitex_cards/_reminder_liveness.py +70 -0
  312. scitex_cards-0.14.0/src/scitex_cards/_reminders.py +510 -0
  313. scitex_cards-0.14.0/src/scitex_cards/_runnable.py +403 -0
  314. scitex_cards-0.14.0/src/scitex_cards/_singleflight.py +124 -0
  315. scitex_cards-0.14.0/src/scitex_cards/_skills/manifest.yaml +54 -0
  316. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/01_installation.md +46 -0
  317. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/02_quick-start.md +51 -0
  318. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/03_python-api.md +85 -0
  319. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/04_cli-reference.md +49 -0
  320. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/05_mcp-tools.md +84 -0
  321. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/10_campaign-tracking.md +75 -0
  322. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/11_adopting-from-a-project.md +205 -0
  323. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/20_env-vars.md +39 -0
  324. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/21_fleet-mcp-rollout.md +182 -0
  325. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/22_pretooluse-hook-redirect.md +48 -0
  326. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/22_skills-propagation.md +140 -0
  327. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/30_two-tier-conventions-and-write-protocol.md +435 -0
  328. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/32_agent-self-consumption-loop.md +142 -0
  329. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/40_task-harvest.md +499 -0
  330. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/41_cli-mcp-gap-analysis.md +247 -0
  331. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/42_for-consuming-agents.md +637 -0
  332. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/50_board-reconciliation-runbook.md +218 -0
  333. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/60_pr-merge-recording-mandate.md +144 -0
  334. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/SKILL.md +322 -0
  335. scitex_cards-0.14.0/src/scitex_cards/_skills/scitex-todo/hooks/pre-tool-use/redirect_claude_tasklist_to_scitex_cards.sh +62 -0
  336. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/.buildinfo +4 -0
  337. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/.doctrees/__intersphinx_cache__/python_objects.inv +0 -0
  338. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/.doctrees/api/scitex_todo.doctree +0 -0
  339. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/.doctrees/cli_reference.doctree +0 -0
  340. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/.doctrees/environment.pickle +0 -0
  341. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/.doctrees/index.doctree +0 -0
  342. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/.doctrees/installation.doctree +0 -0
  343. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/.doctrees/quickstart.doctree +0 -0
  344. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_modules/index.html +144 -0
  345. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_modules/scitex_cards/_model.html +1354 -0
  346. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_modules/scitex_cards/_store.html +1107 -0
  347. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_sources/api/scitex_cards.rst.txt +7 -0
  348. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_sources/cli_reference.rst.txt +42 -0
  349. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_sources/index.rst.txt +89 -0
  350. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_sources/installation.rst.txt +49 -0
  351. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_sources/quickstart.rst.txt +86 -0
  352. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/_sphinx_javascript_frameworks_compat.js +123 -0
  353. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/base-stemmer.js +476 -0
  354. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/basic.css +906 -0
  355. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/check-solid.svg +4 -0
  356. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/clipboard.min.js +7 -0
  357. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/copy-button.svg +5 -0
  358. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/copybutton.css +94 -0
  359. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/copybutton.js +248 -0
  360. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/copybutton_funcs.js +73 -0
  361. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/badge_only.css +1 -0
  362. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/Roboto-Slab-Bold.woff +0 -0
  363. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/Roboto-Slab-Bold.woff2 +0 -0
  364. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/Roboto-Slab-Regular.woff +0 -0
  365. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/Roboto-Slab-Regular.woff2 +0 -0
  366. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/fontawesome-webfont.eot +0 -0
  367. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/fontawesome-webfont.svg +2671 -0
  368. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/fontawesome-webfont.ttf +0 -0
  369. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/fontawesome-webfont.woff +0 -0
  370. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/fontawesome-webfont.woff2 +0 -0
  371. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/lato-bold-italic.woff +0 -0
  372. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/lato-bold-italic.woff2 +0 -0
  373. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/lato-bold.woff +0 -0
  374. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/lato-bold.woff2 +0 -0
  375. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/lato-normal-italic.woff +0 -0
  376. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/lato-normal-italic.woff2 +0 -0
  377. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/lato-normal.woff +0 -0
  378. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/fonts/lato-normal.woff2 +0 -0
  379. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/css/theme.css +4 -0
  380. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/doctools.js +150 -0
  381. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/documentation_options.js +13 -0
  382. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/english-stemmer.js +1066 -0
  383. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/file.png +0 -0
  384. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-bold.eot +0 -0
  385. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-bold.ttf +0 -0
  386. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-bold.woff +0 -0
  387. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-bold.woff2 +0 -0
  388. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-bolditalic.eot +0 -0
  389. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-bolditalic.ttf +0 -0
  390. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-bolditalic.woff +0 -0
  391. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-bolditalic.woff2 +0 -0
  392. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-italic.eot +0 -0
  393. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-italic.ttf +0 -0
  394. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-italic.woff +0 -0
  395. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-italic.woff2 +0 -0
  396. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-regular.eot +0 -0
  397. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-regular.ttf +0 -0
  398. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-regular.woff +0 -0
  399. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/Lato/lato-regular.woff2 +0 -0
  400. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot +0 -0
  401. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf +0 -0
  402. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff +0 -0
  403. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 +0 -0
  404. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot +0 -0
  405. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf +0 -0
  406. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff +0 -0
  407. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 +0 -0
  408. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/jquery.js +2 -0
  409. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/js/badge_only.js +1 -0
  410. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/js/theme.js +1 -0
  411. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/js/versions.js +228 -0
  412. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/language_data.js +13 -0
  413. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/minus.png +0 -0
  414. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/plus.png +0 -0
  415. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/pygments.css +75 -0
  416. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/searchtools.js +693 -0
  417. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/_static/sphinx_highlight.js +159 -0
  418. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/api/scitex_cards.html +436 -0
  419. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/cli_reference.html +204 -0
  420. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/genindex.html +270 -0
  421. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/index.html +269 -0
  422. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/installation.html +204 -0
  423. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/objects.inv +0 -0
  424. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/py-modindex.html +165 -0
  425. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/quickstart.html +244 -0
  426. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/search.html +162 -0
  427. scitex_cards-0.14.0/src/scitex_cards/_sphinx_html/searchindex.js +1 -0
  428. scitex_cards-0.14.0/src/scitex_cards/_stale_active.py +481 -0
  429. scitex_cards-0.14.0/src/scitex_cards/_stale_active_lines.py +146 -0
  430. scitex_cards-0.14.0/src/scitex_cards/_stale_active_nudge.py +533 -0
  431. scitex_cards-0.14.0/src/scitex_cards/_store.py +379 -0
  432. scitex_cards-0.14.0/src/scitex_cards/_store_comment.py +183 -0
  433. scitex_cards-0.14.0/src/scitex_cards/_store_enums.py +107 -0
  434. scitex_cards-0.14.0/src/scitex_cards/_store_events.py +151 -0
  435. scitex_cards-0.14.0/src/scitex_cards/_store_lifecycle.py +478 -0
  436. scitex_cards-0.14.0/src/scitex_cards/_store_list.py +322 -0
  437. scitex_cards-0.14.0/src/scitex_cards/_store_mutate.py +376 -0
  438. scitex_cards-0.14.0/src/scitex_cards/_store_read_sqlite.py +451 -0
  439. scitex_cards-0.14.0/src/scitex_cards/_store_reassign.py +161 -0
  440. scitex_cards-0.14.0/src/scitex_cards/_store_relations.py +233 -0
  441. scitex_cards-0.14.0/src/scitex_cards/_store_verify.py +149 -0
  442. scitex_cards-0.14.0/src/scitex_cards/_store_wip.py +188 -0
  443. scitex_cards-0.14.0/src/scitex_cards/_store_write.py +461 -0
  444. scitex_cards-0.14.0/src/scitex_cards/_task.py +440 -0
  445. scitex_cards-0.14.0/src/scitex_cards/_threads.py +399 -0
  446. scitex_cards-0.14.0/src/scitex_cards/_throughput.py +501 -0
  447. scitex_cards-0.14.0/src/scitex_cards/_turn_url.py +118 -0
  448. scitex_cards-0.14.0/src/scitex_cards/_users/__init__.py +104 -0
  449. scitex_cards-0.14.0/src/scitex_cards/_users/_identity.py +305 -0
  450. scitex_cards-0.14.0/src/scitex_cards/_users/_model.py +373 -0
  451. scitex_cards-0.14.0/src/scitex_cards/_users/_store.py +481 -0
  452. scitex_cards-0.14.0/src/scitex_cards/_validate.py +407 -0
  453. scitex_cards-0.14.0/src/scitex_cards/_wake_watcher.py +509 -0
  454. scitex_cards-0.14.0/src/scitex_cards/_yaml.py +83 -0
  455. scitex_cards-0.14.0/src/scitex_cards/docs/audit/2026-06-13-container-store-divergence.md +270 -0
  456. scitex_cards-0.14.0/src/scitex_cards/examples/.tasks.yaml.lock +0 -0
  457. scitex_cards-0.14.0/src/scitex_cards/examples/config.yaml +33 -0
  458. scitex_cards-0.14.0/src/scitex_cards/examples/tasks.yaml +299 -0
  459. scitex_cards-0.14.0/src/scitex_todo/__init__.py +74 -0
  460. scitex_cards-0.14.0/tests/examples/test_01_render_graph.py +36 -0
  461. scitex_cards-0.14.0/tests/integration/test_cross_package_imports.py +55 -0
  462. scitex_cards-0.14.0/tests/integration/test_peer_edges.py +310 -0
  463. scitex_cards-0.14.0/tests/scitex_cards/_adapters/__init__.py +0 -0
  464. scitex_cards-0.14.0/tests/scitex_cards/_adapters/test__in_process_pubsub.py +22 -0
  465. scitex_cards-0.14.0/tests/scitex_cards/_adapters/test__local_file_sync.py +19 -0
  466. scitex_cards-0.14.0/tests/scitex_cards/_adapters/test__null_liveness.py +17 -0
  467. scitex_cards-0.14.0/tests/scitex_cards/_adapters/test__open_acl.py +17 -0
  468. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__add_echo_and_blocker_none.py +189 -0
  469. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__blocking_operator.py +103 -0
  470. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__board_port_fallback.py +281 -0
  471. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__board_verbs.py +241 -0
  472. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__ci_watch.py +240 -0
  473. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__close.py +357 -0
  474. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__comment.py +129 -0
  475. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__completion.py +36 -0
  476. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__emit.py +306 -0
  477. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__introspect.py +78 -0
  478. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__loop_next.py +216 -0
  479. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__main.py +83 -0
  480. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__mcp_channel_verb.py +43 -0
  481. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__mcp_install_apply.py +320 -0
  482. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__mcp_install_fleet.py +209 -0
  483. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__reconcile.py +83 -0
  484. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__skills.py +48 -0
  485. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__skills_install.py +164 -0
  486. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__skills_propagate.py +296 -0
  487. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__stale.py +181 -0
  488. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__verb_renames.py +354 -0
  489. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__write.py +1053 -0
  490. scitex_cards-0.14.0/tests/scitex_cards/_cli/test__write_blocker_clear.py +162 -0
  491. scitex_cards-0.14.0/tests/scitex_cards/_delivery/__init__.py +1 -0
  492. scitex_cards-0.14.0/tests/scitex_cards/_delivery/_fakes.py +74 -0
  493. scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__channel.py +55 -0
  494. scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__cli_notifyd.py +105 -0
  495. scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__daemon.py +442 -0
  496. scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__ledger.py +201 -0
  497. scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__loop.py +281 -0
  498. scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__pidfile_liveness.py +270 -0
  499. scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__registry.py +114 -0
  500. scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__sweeps.py +180 -0
  501. scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__systemd.py +172 -0
  502. scitex_cards-0.14.0/tests/scitex_cards/_delivery/test__telegram.py +205 -0
  503. scitex_cards-0.14.0/tests/scitex_cards/_diagram/test__mermaid.py +84 -0
  504. scitex_cards-0.14.0/tests/scitex_cards/_diagram/test__render.py +38 -0
  505. scitex_cards-0.14.0/tests/scitex_cards/_django/conftest.py +24 -0
  506. scitex_cards-0.14.0/tests/scitex_cards/_django/frontend/test_calendar_date.py +565 -0
  507. scitex_cards-0.14.0/tests/scitex_cards/_django/frontend/test_chat.py +274 -0
  508. scitex_cards-0.14.0/tests/scitex_cards/_django/frontend/test_chat_helpers.py +301 -0
  509. scitex_cards-0.14.0/tests/scitex_cards/_django/frontend/test_fleet_ci_pills.py +447 -0
  510. scitex_cards-0.14.0/tests/scitex_cards/_django/frontend/test_fleet_timing.py +1084 -0
  511. scitex_cards-0.14.0/tests/scitex_cards/_django/frontend/test_table_filter.py +312 -0
  512. scitex_cards-0.14.0/tests/scitex_cards/_django/frontend/test_timeline.py +254 -0
  513. scitex_cards-0.14.0/tests/scitex_cards/_django/frontend/test_timeline_helpers.py +423 -0
  514. scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/fleet/__init__.py +1 -0
  515. scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/fleet/test_ci_status_view.py +296 -0
  516. scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/fleet/test_gh_ci.py +577 -0
  517. scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/fleet/test_timing.py +629 -0
  518. scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/fleet/test_timing_view.py +192 -0
  519. scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test__chat_view.py +335 -0
  520. scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test__dm_views.py +157 -0
  521. scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test__hooks_views.py +191 -0
  522. scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test__runnable_view.py +181 -0
  523. scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test__timeline_view.py +439 -0
  524. scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test_crud.py +533 -0
  525. scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test_graph_cache.py +108 -0
  526. scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test_graph_fleet.py +446 -0
  527. scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test_graph_roles.py +117 -0
  528. scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test_nudge.py +199 -0
  529. scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test_priority.py +301 -0
  530. scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test_reopen.py +298 -0
  531. scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test_resolve.py +217 -0
  532. scitex_cards-0.14.0/tests/scitex_cards/_django/handlers/test_stale.py +305 -0
  533. scitex_cards-0.14.0/tests/scitex_cards/_django/management/commands/test_scitex_cards_board.py +170 -0
  534. scitex_cards-0.14.0/tests/scitex_cards/_django/test__no_multiline_django_short_comments.py +82 -0
  535. scitex_cards-0.14.0/tests/scitex_cards/_django/test__theme_scrollbar_dropdown.py +499 -0
  536. scitex_cards-0.14.0/tests/scitex_cards/_django/test__toolbar_groups.py +354 -0
  537. scitex_cards-0.14.0/tests/scitex_cards/_django/test_apps.py +32 -0
  538. scitex_cards-0.14.0/tests/scitex_cards/_django/test_lane_union.py +186 -0
  539. scitex_cards-0.14.0/tests/scitex_cards/_django/test_views.py +444 -0
  540. scitex_cards-0.14.0/tests/scitex_cards/_migration/__init__.py +0 -0
  541. scitex_cards-0.14.0/tests/scitex_cards/_migration/test__migrate.py +268 -0
  542. scitex_cards-0.14.0/tests/scitex_cards/_migration/test__migrate_apply.py +235 -0
  543. scitex_cards-0.14.0/tests/scitex_cards/_skills/__init__.py +0 -0
  544. scitex_cards-0.14.0/tests/scitex_cards/_skills/test__no_hand_edit_mandate.py +53 -0
  545. scitex_cards-0.14.0/tests/scitex_cards/_skills/test__pr_merge_recording_mandate.py +98 -0
  546. scitex_cards-0.14.0/tests/scitex_cards/_skills/test__pretooluse_hook.py +116 -0
  547. scitex_cards-0.14.0/tests/scitex_cards/conftest.py +226 -0
  548. scitex_cards-0.14.0/tests/scitex_cards/test__backlog_triage.py +206 -0
  549. scitex_cards-0.14.0/tests/scitex_cards/test__blocked.py +309 -0
  550. scitex_cards-0.14.0/tests/scitex_cards/test__board_v3_signatures.py +752 -0
  551. scitex_cards-0.14.0/tests/scitex_cards/test__cancelled_status.py +279 -0
  552. scitex_cards-0.14.0/tests/scitex_cards/test__card_message_event.py +397 -0
  553. scitex_cards-0.14.0/tests/scitex_cards/test__channel_size_guard.py +220 -0
  554. scitex_cards-0.14.0/tests/scitex_cards/test__completion_stamp_honesty.py +204 -0
  555. scitex_cards-0.14.0/tests/scitex_cards/test__config.py +83 -0
  556. scitex_cards-0.14.0/tests/scitex_cards/test__crash_safe_writer.py +343 -0
  557. scitex_cards-0.14.0/tests/scitex_cards/test__db.py +595 -0
  558. scitex_cards-0.14.0/tests/scitex_cards/test__deadline.py +175 -0
  559. scitex_cards-0.14.0/tests/scitex_cards/test__deadline_multi_recurring.py +255 -0
  560. scitex_cards-0.14.0/tests/scitex_cards/test__deadline_never_notifies.py +263 -0
  561. scitex_cards-0.14.0/tests/scitex_cards/test__digest_ranked.py +82 -0
  562. scitex_cards-0.14.0/tests/scitex_cards/test__dual_write.py +294 -0
  563. scitex_cards-0.14.0/tests/scitex_cards/test__edge_subscribes_waiter.py +156 -0
  564. scitex_cards-0.14.0/tests/scitex_cards/test__entry_points_cached.py +75 -0
  565. scitex_cards-0.14.0/tests/scitex_cards/test__enum_clear.py +302 -0
  566. scitex_cards-0.14.0/tests/scitex_cards/test__events.py +258 -0
  567. scitex_cards-0.14.0/tests/scitex_cards/test__git_link.py +379 -0
  568. scitex_cards-0.14.0/tests/scitex_cards/test__git_link_event_producers.py +342 -0
  569. scitex_cards-0.14.0/tests/scitex_cards/test__group_field.py +206 -0
  570. scitex_cards-0.14.0/tests/scitex_cards/test__groups.py +229 -0
  571. scitex_cards-0.14.0/tests/scitex_cards/test__health.py +323 -0
  572. scitex_cards-0.14.0/tests/scitex_cards/test__health_falsely_blocked.py +196 -0
  573. scitex_cards-0.14.0/tests/scitex_cards/test__health_zombie_cards.py +124 -0
  574. scitex_cards-0.14.0/tests/scitex_cards/test__help_wait.py +313 -0
  575. scitex_cards-0.14.0/tests/scitex_cards/test__hooks.py +480 -0
  576. scitex_cards-0.14.0/tests/scitex_cards/test__hooks_ordering.py +304 -0
  577. scitex_cards-0.14.0/tests/scitex_cards/test__hooks_plugin_timeout.py +274 -0
  578. scitex_cards-0.14.0/tests/scitex_cards/test__idle_guard.py +127 -0
  579. scitex_cards-0.14.0/tests/scitex_cards/test__import_order.py +131 -0
  580. scitex_cards-0.14.0/tests/scitex_cards/test__inbox.py +460 -0
  581. scitex_cards-0.14.0/tests/scitex_cards/test__inbox_digest_collapse.py +191 -0
  582. scitex_cards-0.14.0/tests/scitex_cards/test__inbox_sqlite.py +395 -0
  583. scitex_cards-0.14.0/tests/scitex_cards/test__index.py +294 -0
  584. scitex_cards-0.14.0/tests/scitex_cards/test__install_probe.py +375 -0
  585. scitex_cards-0.14.0/tests/scitex_cards/test__is_overdue.py +135 -0
  586. scitex_cards-0.14.0/tests/scitex_cards/test__jobs_provider.py +104 -0
  587. scitex_cards-0.14.0/tests/scitex_cards/test__mcp_channel.py +544 -0
  588. scitex_cards-0.14.0/tests/scitex_cards/test__mcp_channel_handshake.py +141 -0
  589. scitex_cards-0.14.0/tests/scitex_cards/test__mcp_instructions.py +267 -0
  590. scitex_cards-0.14.0/tests/scitex_cards/test__mcp_server.py +850 -0
  591. scitex_cards-0.14.0/tests/scitex_cards/test__mcp_tools_registered.py +71 -0
  592. scitex_cards-0.14.0/tests/scitex_cards/test__model.py +1397 -0
  593. scitex_cards-0.14.0/tests/scitex_cards/test__next.py +266 -0
  594. scitex_cards-0.14.0/tests/scitex_cards/test__notify_config.py +470 -0
  595. scitex_cards-0.14.0/tests/scitex_cards/test__notify_dispatch.py +424 -0
  596. scitex_cards-0.14.0/tests/scitex_cards/test__org.py +238 -0
  597. scitex_cards-0.14.0/tests/scitex_cards/test__org_multi_recurring.py +115 -0
  598. scitex_cards-0.14.0/tests/scitex_cards/test__owner_ssot.py +230 -0
  599. scitex_cards-0.14.0/tests/scitex_cards/test__parked.py +203 -0
  600. scitex_cards-0.14.0/tests/scitex_cards/test__paths.py +222 -0
  601. scitex_cards-0.14.0/tests/scitex_cards/test__pending_backlog.py +187 -0
  602. scitex_cards-0.14.0/tests/scitex_cards/test__ports_and_adapters.py +525 -0
  603. scitex_cards-0.14.0/tests/scitex_cards/test__print_stats_single_instance.py +200 -0
  604. scitex_cards-0.14.0/tests/scitex_cards/test__push.py +571 -0
  605. scitex_cards-0.14.0/tests/scitex_cards/test__reassign_all.py +278 -0
  606. scitex_cards-0.14.0/tests/scitex_cards/test__recent_view.js +285 -0
  607. scitex_cards-0.14.0/tests/scitex_cards/test__recent_view_module.py +234 -0
  608. scitex_cards-0.14.0/tests/scitex_cards/test__reconcile_prs.py +289 -0
  609. scitex_cards-0.14.0/tests/scitex_cards/test__reminders.py +780 -0
  610. scitex_cards-0.14.0/tests/scitex_cards/test__runnable.py +335 -0
  611. scitex_cards-0.14.0/tests/scitex_cards/test__search_query.js +277 -0
  612. scitex_cards-0.14.0/tests/scitex_cards/test__search_query_module.py +135 -0
  613. scitex_cards-0.14.0/tests/scitex_cards/test__search_suggest.js +339 -0
  614. scitex_cards-0.14.0/tests/scitex_cards/test__search_suggest_module.py +180 -0
  615. scitex_cards-0.14.0/tests/scitex_cards/test__stale_active.py +213 -0
  616. scitex_cards-0.14.0/tests/scitex_cards/test__stale_active_blocker_aware.py +220 -0
  617. scitex_cards-0.14.0/tests/scitex_cards/test__stale_active_nudge.py +434 -0
  618. scitex_cards-0.14.0/tests/scitex_cards/test__store.py +1036 -0
  619. scitex_cards-0.14.0/tests/scitex_cards/test__store_assignee_liveness.py +145 -0
  620. scitex_cards-0.14.0/tests/scitex_cards/test__store_card_events.py +474 -0
  621. scitex_cards-0.14.0/tests/scitex_cards/test__store_concurrency.py +126 -0
  622. scitex_cards-0.14.0/tests/scitex_cards/test__store_doc_preservation.py +218 -0
  623. scitex_cards-0.14.0/tests/scitex_cards/test__store_git_gc.py +115 -0
  624. scitex_cards-0.14.0/tests/scitex_cards/test__store_read_sqlite.py +510 -0
  625. scitex_cards-0.14.0/tests/scitex_cards/test__store_verbs.py +708 -0
  626. scitex_cards-0.14.0/tests/scitex_cards/test__store_verify.py +284 -0
  627. scitex_cards-0.14.0/tests/scitex_cards/test__store_wip.py +260 -0
  628. scitex_cards-0.14.0/tests/scitex_cards/test__threads.py +247 -0
  629. scitex_cards-0.14.0/tests/scitex_cards/test__throughput.py +534 -0
  630. scitex_cards-0.14.0/tests/scitex_cards/test__timeline_controls.js +142 -0
  631. scitex_cards-0.14.0/tests/scitex_cards/test__timeline_gate.js +152 -0
  632. scitex_cards-0.14.0/tests/scitex_cards/test__timeline_geo.js +85 -0
  633. scitex_cards-0.14.0/tests/scitex_cards/test__timeline_pack.js +173 -0
  634. scitex_cards-0.14.0/tests/scitex_cards/test__timeline_select.js +115 -0
  635. scitex_cards-0.14.0/tests/scitex_cards/test__users.py +471 -0
  636. scitex_cards-0.14.0/tests/scitex_cards/test__users_identity.py +232 -0
  637. scitex_cards-0.14.0/tests/scitex_cards/test__users_write_preserves_tasks_fast.py +107 -0
  638. scitex_cards-0.14.0/tests/scitex_cards/test__wake_watcher.py +708 -0
  639. scitex_cards-0.14.0/tests/test_board_handlers_use_cached_read.py +64 -0
  640. scitex_cards-0.14.0/tests/test_cli_gui.py +90 -0
  641. scitex_cards-0.14.0/tests/test_db_mirror_incremental.py +217 -0
  642. scitex_cards-0.14.0/tests/test_deadline_tz_aware.py +103 -0
  643. scitex_cards-0.14.0/tests/test_reminder_cadence.py +109 -0
  644. 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,2 @@
1
+ # Sphinx-generated docs bundle — exclude from GitHub language stats.
2
+ src/*/_sphinx_html/** linguist-generated
@@ -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)"