tcw-cli 2.8.2__tar.gz → 2.8.3__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 (233) hide show
  1. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/PKG-INFO +1 -1
  2. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/pyproject.toml +1 -1
  3. tcw_cli-2.8.3/tcw/__init__.py +1 -0
  4. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/tracker/jira.py +5 -1
  5. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw_cli.egg-info/PKG-INFO +1 -1
  6. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_client.py +63 -1
  7. tcw_cli-2.8.2/tcw/__init__.py +0 -1
  8. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/LICENSE +0 -0
  9. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/README.md +0 -0
  10. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/setup.cfg +0 -0
  11. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/capabilities/__init__.py +0 -0
  12. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/capabilities/cli.py +0 -0
  13. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/cli.py +0 -0
  14. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/cli_suggest.py +0 -0
  15. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/harness.py +0 -0
  16. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/refs.py +0 -0
  17. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/serve/__init__.py +0 -0
  18. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/serve/dist/client/assets/index-C5_pngMt.css +0 -0
  19. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/serve/dist/client/assets/index-Dss8_ZG_.js +0 -0
  20. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/serve/dist/client/index.html +0 -0
  21. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/serve/dist/client/theme-init.js +0 -0
  22. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/serve/dist/server.cjs +0 -0
  23. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/serve/runtime.py +0 -0
  24. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/stdin.py +0 -0
  25. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/store/__init__.py +0 -0
  26. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/store/base.py +0 -0
  27. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/store/checkouts.py +0 -0
  28. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/store/config_edit.py +0 -0
  29. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/store/fs.py +0 -0
  30. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/store/project.py +0 -0
  31. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/store/yaml_source.py +0 -0
  32. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/taxonomy/__init__.py +0 -0
  33. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/taxonomy/cli.py +0 -0
  34. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/tracker/__init__.py +0 -0
  35. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/tracker/claim.py +0 -0
  36. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/tracker/create.py +0 -0
  37. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/tracker/intake.py +0 -0
  38. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/tracker/ownership.py +0 -0
  39. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/tracker/progress.py +0 -0
  40. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/tracker/sync.py +0 -0
  41. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/validate.py +0 -0
  42. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/__init__.py +0 -0
  43. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/cli.py +0 -0
  44. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/generate.py +0 -0
  45. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/hooks.py +0 -0
  46. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/procedures/audit-backlog.md +0 -0
  47. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/procedures/consolidate-plans.md +0 -0
  48. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/procedures/create-work.md +0 -0
  49. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/procedures/decompose.md +0 -0
  50. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/procedures/delegation.md +0 -0
  51. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/procedures/documentation-sync.md +0 -0
  52. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/procedures/post-mortem.md +0 -0
  53. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/procedures/search.md +0 -0
  54. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/procedures/triage-issues.md +0 -0
  55. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/procedures/unattended-work.md +0 -0
  56. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/projection.py +0 -0
  57. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/prompts/implement.md +0 -0
  58. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/prompts/inbox.md +0 -0
  59. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/prompts/plan.md +0 -0
  60. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/prompts/postmortem.md +0 -0
  61. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/prompts/request.md +0 -0
  62. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/prompts/spec.md +0 -0
  63. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/prompts/verify.md +0 -0
  64. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/recursion.py +0 -0
  65. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/resolve.py +0 -0
  66. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw/work/templates.py +0 -0
  67. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw_cli.egg-info/SOURCES.txt +0 -0
  68. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw_cli.egg-info/dependency_links.txt +0 -0
  69. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw_cli.egg-info/entry_points.txt +0 -0
  70. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw_cli.egg-info/requires.txt +0 -0
  71. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tcw_cli.egg-info/top_level.txt +0 -0
  72. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_already_integrated_check.py +0 -0
  73. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_blocker_cycles_through_unreadable_items.py +0 -0
  74. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_boardless_delegate_and_slices.py +0 -0
  75. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_body_prompt.py +0 -0
  76. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_capabilities.py +0 -0
  77. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_capabilities_federation.py +0 -0
  78. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_capabilities_reset.py +0 -0
  79. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_capabilities_rm.py +0 -0
  80. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_capabilities_sidecar.py +0 -0
  81. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_capability_gate_children.py +0 -0
  82. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_capability_ref_wording.py +0 -0
  83. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_check_versions.py +0 -0
  84. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_child_status.py +0 -0
  85. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_cli_help_coverage.py +0 -0
  86. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_command_suggestions.py +0 -0
  87. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_committed_paths.py +0 -0
  88. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_config_edit.py +0 -0
  89. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_config_edit_writers.py +0 -0
  90. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_configuration_text_home.py +0 -0
  91. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_creation_commits.py +0 -0
  92. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_cross_node_blocker_cycles.py +0 -0
  93. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_cross_node_blockers.py +0 -0
  94. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_cut_version.py +0 -0
  95. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_damaged_state_on_edit.py +0 -0
  96. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_detached_worktree_teardown.py +0 -0
  97. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_documentation_config.py +0 -0
  98. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_documentation_prompt.py +0 -0
  99. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_documentation_sync_wiring.py +0 -0
  100. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_documented_cli_surface.py +0 -0
  101. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_duplicate_slug_refusals.py +0 -0
  102. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_dynamic_skill_marker.py +0 -0
  103. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_edit_refusal.py +0 -0
  104. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_edit_type.py +0 -0
  105. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_environment_hardness.py +0 -0
  106. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_epic_completability_across_checkouts.py +0 -0
  107. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_epic_completable.py +0 -0
  108. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_eval_coverage.py +0 -0
  109. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_eval_files_changed.py +0 -0
  110. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_eval_fixture.py +0 -0
  111. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_eval_grading.py +0 -0
  112. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_eval_runner.py +0 -0
  113. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_external_work_store.py +0 -0
  114. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_falsification_rule.py +0 -0
  115. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_generate_hook.py +0 -0
  116. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_harness.py +0 -0
  117. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_inbox_title.py +0 -0
  118. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_init_configured_tree_path.py +0 -0
  119. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_initiative_node_qualified.py +0 -0
  120. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_interrupted_claim.py +0 -0
  121. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_item_tags_read.py +0 -0
  122. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_legacy_store_config.py +0 -0
  123. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_lifecycle_baseline.py +0 -0
  124. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_lifecycle_config_tags.py +0 -0
  125. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_lifecycle_hooks.py +0 -0
  126. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_lifecycle_inert.py +0 -0
  127. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_lifecycle_policy.py +0 -0
  128. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_lifecycle_validation.py +0 -0
  129. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_literal_store_names.py +0 -0
  130. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_local_qualified_blockers.py +0 -0
  131. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_multiproject.py +0 -0
  132. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_non_git_writes.py +0 -0
  133. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_override_in_linked_worktree.py +0 -0
  134. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_override_letter_case.py +0 -0
  135. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_override_references.py +0 -0
  136. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_planning_gates_after_start.py +0 -0
  137. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_plugin_manifests.py +0 -0
  138. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_procedure_config.py +0 -0
  139. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_procedure_verb.py +0 -0
  140. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_project_graph_paths.py +0 -0
  141. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_project_overrides.py +0 -0
  142. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_project_registry.py +0 -0
  143. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_projection.py +0 -0
  144. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_prompt_fallback.py +0 -0
  145. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_qualified_ref.py +0 -0
  146. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_recursion.py +0 -0
  147. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_refs.py +0 -0
  148. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_remote_session_setup.py +0 -0
  149. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_rename_work_item.py +0 -0
  150. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_repo_lifecycle.py +0 -0
  151. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_resolve.py +0 -0
  152. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_resolve_procedure.py +0 -0
  153. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_retention.py +0 -0
  154. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_routing_nodes.py +0 -0
  155. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_scaffold.py +0 -0
  156. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_serve.py +0 -0
  157. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_serve_descendants.py +0 -0
  158. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_serve_duplicate_slug.py +0 -0
  159. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_serve_projection.py +0 -0
  160. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_serve_resolve.py +0 -0
  161. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_serve_runtime.py +0 -0
  162. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_serve_write.py +0 -0
  163. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_session_bootstrap.py +0 -0
  164. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_shipped_procedures.py +0 -0
  165. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_shipped_prompts.py +0 -0
  166. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_show_json.py +0 -0
  167. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_sidecar_paths_in_validate.py +0 -0
  168. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_skill_flow.py +0 -0
  169. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_skill_lifecycle_parity.py +0 -0
  170. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_skill_path_pointers.py +0 -0
  171. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_smoke.py +0 -0
  172. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_stage_validate.py +0 -0
  173. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_stage_verb.py +0 -0
  174. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_stale_item_path.py +0 -0
  175. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_status_parity.py +0 -0
  176. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_stdin.py +0 -0
  177. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_stdin_cli.py +0 -0
  178. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_store_bounds.py +0 -0
  179. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_store_editor.py +0 -0
  180. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_store_lock.py +0 -0
  181. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_store_nodes.py +0 -0
  182. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_store_provisioning.py +0 -0
  183. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_store_publication.py +0 -0
  184. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_subprocess_stdin.py +0 -0
  185. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_taxonomy.py +0 -0
  186. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_taxonomy_rm_gaps.py +0 -0
  187. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tombstone.py +0 -0
  188. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_absent.py +0 -0
  189. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_binding.py +0 -0
  190. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_catch_up_moves.py +0 -0
  191. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_claim.py +0 -0
  192. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_claimability.py +0 -0
  193. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_cli.py +0 -0
  194. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_comment.py +0 -0
  195. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_config.py +0 -0
  196. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_create.py +0 -0
  197. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_gate.py +0 -0
  198. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_hardening.py +0 -0
  199. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_help.py +0 -0
  200. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_hold.py +0 -0
  201. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_import.py +0 -0
  202. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_import_returns.py +0 -0
  203. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_inheritance.py +0 -0
  204. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_link.py +0 -0
  205. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_message_tidy.py +0 -0
  206. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_ownership.py +0 -0
  207. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_pre_backlog.py +0 -0
  208. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_replay.py +0 -0
  209. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_strict.py +0 -0
  210. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_strict_gate.py +0 -0
  211. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_surface.py +0 -0
  212. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_sync.py +0 -0
  213. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_sync_config.py +0 -0
  214. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_tracker_validate.py +0 -0
  215. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_transition_hints.py +0 -0
  216. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_unattended_work_skill.py +0 -0
  217. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_unplanned_start.py +0 -0
  218. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_unpushed_version_script.py +0 -0
  219. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_unreadable_capabilities_sidecar.py +0 -0
  220. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_unreadable_item_files.py +0 -0
  221. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_unreadable_state_gates.py +0 -0
  222. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_untag_invalid_tags.py +0 -0
  223. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_upstream_projects.py +0 -0
  224. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_validate.py +0 -0
  225. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_validate_moved_stores.py +0 -0
  226. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_validate_target.py +0 -0
  227. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_work.py +0 -0
  228. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_work_autocommit.py +0 -0
  229. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_work_review.py +0 -0
  230. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_work_start.py +0 -0
  231. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_work_tags.py +0 -0
  232. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_worktree_completion.py +0 -0
  233. {tcw_cli-2.8.2 → tcw_cli-2.8.3}/tests/test_worktree_sibling_nodes.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tcw-cli
3
- Version: 2.8.2
3
+ Version: 2.8.3
4
4
  Summary: Taxonomy · Capabilities · Work — a storage-abstracted framework for describing and evolving a software project.
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tcw-cli"
7
- version = "2.8.2"
7
+ version = "2.8.3"
8
8
  description = "Taxonomy · Capabilities · Work — a storage-abstracted framework for describing and evolving a software project."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -0,0 +1 @@
1
+ __version__ = "2.8.3"
@@ -149,7 +149,11 @@ class JiraClient:
149
149
  request = urllib.request.Request(
150
150
  f"{self.config.base_url}{path}", data=payload, method=method)
151
151
  credentials = base64.b64encode(f"{email}:{token}".encode("utf-8")).decode("ascii")
152
- request.add_header("Authorization", f"Basic {credentials}")
152
+ # Unredirected: urllib copies every `add_header` header onto the request a
153
+ # redirect produces, whatever host it points at, which would hand the
154
+ # user's email and API token to that host. A redirected request now goes
155
+ # without them.
156
+ request.add_unredirected_header("Authorization", f"Basic {credentials}")
153
157
  request.add_header("Accept", "application/json")
154
158
  if payload is not None:
155
159
  request.add_header("Content-Type", "application/json")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tcw-cli
3
- Version: 2.8.2
3
+ Version: 2.8.3
4
4
  Summary: Taxonomy · Capabilities · Work — a storage-abstracted framework for describing and evolving a software project.
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -300,7 +300,9 @@ def test_the_authorization_header_is_built_from_the_named_variables(monkeypatch)
300
300
  captured = {}
301
301
 
302
302
  def fake_urlopen(request, timeout=None):
303
- captured["headers"] = dict(request.headers)
303
+ # `header_items()` rather than `headers`: the authorization header is
304
+ # an unredirected one, which `headers` does not include.
305
+ captured["headers"] = dict(request.header_items())
304
306
  captured["timeout"] = timeout
305
307
  captured["url"] = request.full_url
306
308
 
@@ -501,3 +503,63 @@ def test_a_server_that_drops_the_connection_is_unavailable_not_a_crash():
501
503
  finally:
502
504
  thread.join(timeout=5)
503
505
  listener.close()
506
+
507
+
508
+ def test_a_redirect_to_another_host_does_not_carry_the_credentials():
509
+ """urllib copies every header added with `add_header` onto the request a
510
+ redirect produces, whatever host it points at. So the authorization header has
511
+ to be an unredirected one, or a redirect from the tracker (or anything between
512
+ it and us) to another host receives the user's email and API token. Two real
513
+ local servers: the first answers 302 to the second, under a different host
514
+ name and port, and the second records what it was sent."""
515
+ import http.server
516
+ import threading
517
+
518
+ seen = {}
519
+
520
+ def handler(name, answer):
521
+ class Handler(http.server.BaseHTTPRequestHandler):
522
+ def do_GET(self):
523
+ seen[name] = self.headers.get("Authorization")
524
+ answer(self)
525
+
526
+ def log_message(self, *args):
527
+ pass
528
+ return Handler
529
+
530
+ def ok(request_handler):
531
+ body = b"{}"
532
+ request_handler.send_response(200)
533
+ request_handler.send_header("Content-Type", "application/json")
534
+ request_handler.send_header("Content-Length", str(len(body)))
535
+ request_handler.end_headers()
536
+ request_handler.wfile.write(body)
537
+
538
+ other = http.server.HTTPServer(("127.0.0.1", 0), handler("other", ok))
539
+ other_port = other.server_address[1]
540
+
541
+ def redirect(request_handler):
542
+ request_handler.send_response(302)
543
+ request_handler.send_header(
544
+ "Location", f"http://localhost:{other_port}/rest/api/3/myself")
545
+ request_handler.send_header("Content-Length", "0")
546
+ request_handler.end_headers()
547
+
548
+ tracker = http.server.HTTPServer(("127.0.0.1", 0), handler("tracker", redirect))
549
+ servers = (tracker, other)
550
+ threads = [threading.Thread(target=s.serve_forever, daemon=True) for s in servers]
551
+ for thread in threads:
552
+ thread.start()
553
+ try:
554
+ config = dataclasses.replace(
555
+ CONFIG, base_url=f"http://127.0.0.1:{tracker.server_address[1]}",
556
+ timeout_seconds=5)
557
+ jira.JiraClient(config).myself()
558
+ finally:
559
+ for server in servers:
560
+ server.shutdown()
561
+ server.server_close()
562
+
563
+ assert seen["tracker"] is not None and seen["tracker"].startswith("Basic ")
564
+ assert "other" in seen, "the redirect was never followed"
565
+ assert seen["other"] is None
@@ -1 +0,0 @@
1
- __version__ = "2.8.2"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes