tcw-cli 3.0.1__tar.gz → 3.0.2__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 (178) hide show
  1. {tcw_cli-3.0.1/tcw_cli.egg-info → tcw_cli-3.0.2}/PKG-INFO +1 -1
  2. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/pyproject.toml +1 -1
  3. tcw_cli-3.0.2/tcw/__init__.py +1 -0
  4. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/store/project.py +2 -2
  5. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/jira/tickets.py +3 -1
  6. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/prompts/plan.md +8 -2
  7. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/prompts/request.md +2 -1
  8. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/prompts/spec.md +2 -0
  9. {tcw_cli-3.0.1 → tcw_cli-3.0.2/tcw_cli.egg-info}/PKG-INFO +1 -1
  10. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_project_registry.py +5 -6
  11. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_prompt_fallback.py +5 -0
  12. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_repo_lifecycle.py +1 -0
  13. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_shipped_prompts.py +27 -0
  14. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_store_provisioning.py +18 -18
  15. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_upstream_projects.py +22 -22
  16. tcw_cli-3.0.1/tcw/__init__.py +0 -1
  17. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/LICENSE +0 -0
  18. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/README.md +0 -0
  19. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/setup.cfg +0 -0
  20. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/capabilities/__init__.py +0 -0
  21. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/capabilities/cli.py +0 -0
  22. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/cli.py +0 -0
  23. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/cli_help.py +0 -0
  24. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/cli_suggest.py +0 -0
  25. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/config.py +0 -0
  26. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/config_cli.py +0 -0
  27. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/errors.py +0 -0
  28. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/exit.py +0 -0
  29. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/findings.py +0 -0
  30. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/output.py +0 -0
  31. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/projects_cli.py +0 -0
  32. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/refs.py +0 -0
  33. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/serve/__init__.py +0 -0
  34. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/serve/dist/client/assets/index-BGwvKkRc.js +0 -0
  35. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/serve/dist/client/assets/index-DkarCRfj.css +0 -0
  36. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/serve/dist/client/index.html +0 -0
  37. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/serve/dist/client/theme-init.js +0 -0
  38. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/serve/files.py +0 -0
  39. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/serve/records.py +0 -0
  40. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/serve/server.py +0 -0
  41. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/serve/services.py +0 -0
  42. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/serve/work.py +0 -0
  43. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/stdin.py +0 -0
  44. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/store/__init__.py +0 -0
  45. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/store/base.py +0 -0
  46. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/store/checkouts.py +0 -0
  47. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/store/config_edit.py +0 -0
  48. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/store/fs.py +0 -0
  49. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/store/yaml_source.py +0 -0
  50. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/taxonomy/__init__.py +0 -0
  51. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/taxonomy/cli.py +0 -0
  52. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/validate.py +0 -0
  53. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/__init__.py +0 -0
  54. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/advance.py +0 -0
  55. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/backend.py +0 -0
  56. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/cli.py +0 -0
  57. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/config.py +0 -0
  58. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/fs_backend.py +0 -0
  59. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/gates.py +0 -0
  60. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/generate.py +0 -0
  61. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/hooks.py +0 -0
  62. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/jira/__init__.py +0 -0
  63. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/jira/backend.py +0 -0
  64. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/jira/client.py +0 -0
  65. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/jira/config.py +0 -0
  66. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/jira/jql.py +0 -0
  67. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/jira/mapping.py +0 -0
  68. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/jira/remote.py +0 -0
  69. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/layout.py +0 -0
  70. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/model.py +0 -0
  71. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/open.py +0 -0
  72. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/passages.py +0 -0
  73. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/procedures/audit-backlog.md +0 -0
  74. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/procedures/create-work.md +0 -0
  75. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/procedures/documentation-sync.md +0 -0
  76. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/procedures/pause-work.md +0 -0
  77. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/procedures/search.md +0 -0
  78. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/procedures/triage-issues.md +0 -0
  79. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/procedures/unattended-work.md +0 -0
  80. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/prompts/implement.md +0 -0
  81. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/prompts/inbox.md +0 -0
  82. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/prompts/postmortem.md +0 -0
  83. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/prompts/qa.md +0 -0
  84. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/prompts/review.md +0 -0
  85. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/record.py +0 -0
  86. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/references.py +0 -0
  87. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw/work/resolve.py +0 -0
  88. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw_cli.egg-info/SOURCES.txt +0 -0
  89. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw_cli.egg-info/dependency_links.txt +0 -0
  90. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw_cli.egg-info/entry_points.txt +0 -0
  91. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw_cli.egg-info/requires.txt +0 -0
  92. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tcw_cli.egg-info/top_level.txt +0 -0
  93. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_capabilities.py +0 -0
  94. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_capabilities_cli_contract.py +0 -0
  95. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_capabilities_federation.py +0 -0
  96. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_capabilities_reset.py +0 -0
  97. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_capabilities_rm.py +0 -0
  98. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_capability_ref_wording.py +0 -0
  99. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_check_versions.py +0 -0
  100. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_cli_contract.py +0 -0
  101. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_cli_guide.py +0 -0
  102. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_cli_handler.py +0 -0
  103. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_cli_help_standard.py +0 -0
  104. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_command_suggestions.py +0 -0
  105. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_committed_paths.py +0 -0
  106. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_config_edit.py +0 -0
  107. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_config_edit_writers.py +0 -0
  108. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_configuration_text_home.py +0 -0
  109. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_cut_version.py +0 -0
  110. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_doc_vocabulary.py +0 -0
  111. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_docs_describe_3_0.py +0 -0
  112. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_documentation_config.py +0 -0
  113. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_documentation_prompt.py +0 -0
  114. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_documentation_sync_wiring.py +0 -0
  115. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_documented_cli_surface.py +0 -0
  116. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_dynamic_skill_marker.py +0 -0
  117. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_environment_hardness.py +0 -0
  118. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_eval_coverage.py +0 -0
  119. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_eval_files_changed.py +0 -0
  120. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_eval_fixture.py +0 -0
  121. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_eval_grading.py +0 -0
  122. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_eval_runner.py +0 -0
  123. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_falsification_rule.py +0 -0
  124. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_findings_type.py +0 -0
  125. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_generate_hook.py +0 -0
  126. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_git_example.py +0 -0
  127. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_init_configured_tree_path.py +0 -0
  128. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_init_provision_contract.py +0 -0
  129. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_item_tags_read.py +0 -0
  130. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_ledger_3_0.py +0 -0
  131. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_legacy_store_config.py +0 -0
  132. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_lifecycle_config_tags.py +0 -0
  133. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_literal_store_names.py +0 -0
  134. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_migration_guide.py +0 -0
  135. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_multiproject.py +0 -0
  136. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_no_node.py +0 -0
  137. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_override_in_linked_worktree.py +0 -0
  138. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_override_letter_case.py +0 -0
  139. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_override_references.py +0 -0
  140. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_partial_removal.py +0 -0
  141. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_plugin_manifests.py +0 -0
  142. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_procedure_config.py +0 -0
  143. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_procedure_verb.py +0 -0
  144. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_project_graph_paths.py +0 -0
  145. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_project_overrides.py +0 -0
  146. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_projects_list.py +0 -0
  147. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_refs.py +0 -0
  148. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_remote_session_setup.py +0 -0
  149. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_require_artifact.py +0 -0
  150. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_routing_nodes.py +0 -0
  151. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_session_bootstrap.py +0 -0
  152. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_shipped_procedures.py +0 -0
  153. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_shipped_text.py +0 -0
  154. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_skill_flow.py +0 -0
  155. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_skill_path_pointers.py +0 -0
  156. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_smoke.py +0 -0
  157. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_stage_verb.py +0 -0
  158. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_static_guards.py +0 -0
  159. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_stdin.py +0 -0
  160. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_stdin_cli.py +0 -0
  161. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_store_bounds.py +0 -0
  162. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_store_editor.py +0 -0
  163. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_store_nodes.py +0 -0
  164. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_subprocess_stdin.py +0 -0
  165. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_suite_runs_its_own_tcw.py +0 -0
  166. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_taxonomy.py +0 -0
  167. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_taxonomy_cli_contract.py +0 -0
  168. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_taxonomy_rm_gaps.py +0 -0
  169. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_tree_store_files_only.py +0 -0
  170. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_tree_store_raises.py +0 -0
  171. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_unattended_work_skill.py +0 -0
  172. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_unpushed_version_script.py +0 -0
  173. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_upcoming_entries.py +0 -0
  174. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_validate.py +0 -0
  175. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_validate_command.py +0 -0
  176. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_validate_moved_stores.py +0 -0
  177. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/tests/test_validate_target.py +0 -0
  178. {tcw_cli-3.0.1 → tcw_cli-3.0.2}/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: 3.0.1
3
+ Version: 3.0.2
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 = "3.0.1"
7
+ version = "3.0.2"
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__ = "3.0.2"
@@ -39,8 +39,8 @@ def validate_project_id(project_id: str) -> str:
39
39
  def override_variable(project_id: str) -> str:
40
40
  """The environment variable that says where `project_id` lives on this machine.
41
41
 
42
- The id, uppercased, with `-` as `_`: `proposit-core` →
43
- `TCW_PROJECT_PROPOSIT_CORE`. **Project ids, not repository names** — the two are
42
+ The id, uppercased, with `-` as `_`: `app-repo` →
43
+ `TCW_PROJECT_APP_REPO`. **Project ids, not repository names** — the two are
44
44
  routinely different, and a workspace where they are crossed is what this
45
45
  mapping is most often got wrong against.
46
46
 
@@ -392,7 +392,9 @@ def delegate_to_jira(project_id: str, title: str, request: str | None,
392
392
  raise _named(BackendError(f"created {key} for {project_id}, but did not finish "
393
393
  f"making it the item {slug}: {error}; finish with "
394
394
  f"`tcw work tickets adopt {key}` there"), key) from None
395
- report(f"the new files in {backend.work_path / slug.folder} are left uncommitted")
395
+ report(f"the new files in {backend.work_path / slug.folder} are left uncommitted; "
396
+ f"record them in that project's version control before filing into "
397
+ f"{project_id} again, or the next ticket stays in its Jira inbox")
396
398
  return str(slug)
397
399
 
398
400
 
@@ -36,8 +36,14 @@ tests cannot check.
36
36
  5. Record dependencies between items as blockers, not prose:
37
37
  `tcw work edit <slug> --blocked-by <ref>`.
38
38
  6. **Too large for one item?** Split it here: `tcw work new "<title>" --parent
39
- <slug>` for each part, the part's request on stdin, and plan this item as
40
- the parent that ties them together.
39
+ <slug>` per part, its request on stdin; this item is the parent. A part for
40
+ another project: `tcw work new "<title>" --project <id>` (no `--parent`). A
41
+ ticket key printed instead of a slug means no item exists there yet: report
42
+ it. Otherwise, from inside that project, set `--parent` (a Jira project
43
+ takes only a ticket on its own site) and `--blocked-by` with `tcw work edit`,
44
+ then record TCW's uncommitted changes in that project's version control
45
+ before filing there again: until then a filing is refused, or its Jira
46
+ ticket stays in the inbox.
41
47
  7. **No placeholders.** "TBD", "add error handling", "as in step 3": a step
42
48
  nobody can carry out without asking you a question is not a step.
43
49
  8. **Self-review.** Re-read the plan against the spec: every acceptance
@@ -40,7 +40,8 @@ the requester to adopt.
40
40
  The requester decides when the request is ready. When they tell you to move
41
41
  the item on, in this conversation, do it. If they adopted changed wording,
42
42
  first put it into the ticket's description: write it yourself if your harness
43
- can edit Jira tickets, or ask them to paste it in. Then read it back and
43
+ can edit Jira tickets, or ask them to paste it in. Change only what they
44
+ adopted, and keep everything else in the description. Then read it back and
44
45
  confirm the description now says what they adopted. Then run
45
46
  `tcw work advance <slug> --reason "<who told you to move it>"`. A question,
46
47
  such as whether accepting the wording moves the item, is not an instruction to
@@ -51,6 +51,8 @@ it to `tcw work path <slug> spec --handoff`.
51
51
 
52
52
  - _The code contradicts the request._ Stop and return to request. A spec that
53
53
  quietly reinterprets the request is worse than one that refuses.
54
+ - _The requester revises the request._ It stays at spec: record it as an
55
+ amendment (a dated `## Added`; in Jira, an `Added` comment), and follow it.
54
56
  - _The work is too large for one item._ Say so; plan decomposes it.
55
57
  - _You cannot ground a claim._ Mark it as an assumption, not a fact.
56
58
  - _`tcw work comment` failed._ Report the command and its exit code, do not
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tcw-cli
3
- Version: 3.0.1
3
+ Version: 3.0.2
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
@@ -66,13 +66,12 @@ def test_the_override_variable_name_follows_the_id():
66
66
  """The id, uppercased with `-` as `_` — node ids, never repository names.
67
67
 
68
68
  The distinction costs an hour when the two are crossed, which they are in
69
- the workspace that prompted this: the directory `proposit-orchestration`
70
- holds the node `proposit-app`, and the directory `proposit-app` holds the
71
- node `proposit-app-repo`.
69
+ the workspace that prompted this: the directory `workspace` holds the
70
+ node `product`, and the directory `app` holds the node `app-repo`.
72
71
  """
73
- assert override_variable("proposit-core") == "TCW_PROJECT_PROPOSIT_CORE"
74
- assert override_variable("proposit-app") == "TCW_PROJECT_PROPOSIT_APP"
75
- assert override_variable("proposit-app-repo") == "TCW_PROJECT_PROPOSIT_APP_REPO"
72
+ assert override_variable("app-repo") == "TCW_PROJECT_APP_REPO"
73
+ assert override_variable("product") == "TCW_PROJECT_PRODUCT"
74
+ assert override_variable("app-repo-web") == "TCW_PROJECT_APP_REPO_WEB"
76
75
  assert override_variable("a") == "TCW_PROJECT_A"
77
76
 
78
77
 
@@ -21,6 +21,11 @@ re-baselining to hide that is what this file exists to prevent.
21
21
  **Re-captured again by TCW-76**, for one paragraph only: TCW-74's review fixes
22
22
  (`e411e681`) added "Who reviews" to the review prompt after the capture, and
23
23
  the recorded bytes were never brought up to it. Nothing else moved.
24
+
25
+ **Re-captured again by TCW-101**, for two passages it added on purpose: the
26
+ spec prompt's "The requester revises the request" bullet, and the plan
27
+ prompt's step 6 on filing a part into another project. A diff of the old and
28
+ new bytes showed nothing else moved.
24
29
  """
25
30
 
26
31
  import json
@@ -47,6 +47,7 @@ DOCUMENTATION = {
47
47
  ("docs/changelogs/upcoming/<folder>.md", "Any-Code-Change"),
48
48
  ("skills/<component>/SKILL.md", "Skill-Driven-Component"),
49
49
  ("skills/configure/references/<document>.md", "Configuration-Key-Change"),
50
+ ("docs/use-cases.md", "Project-Setup-Change"),
50
51
  }
51
52
 
52
53
  # Programs a `command:` hook runs a script with; the script is then its
@@ -311,3 +311,30 @@ def test_the_self_review_pass_appears_in_exactly_three_prompts():
311
311
  prompts = load_builtins().stage_prompts
312
312
  found = {sid for sid, text in prompts.items() if "self-review" in text.lower()}
313
313
  assert found == {"spec", "plan", "implement"}
314
+
315
+
316
+ def test_jira_request_keeps_what_the_requester_did_not_change():
317
+ """TCW-101: adopted wording changes only what was adopted."""
318
+ paragraph = _paragraph_with(prompt("request", "jira"), "tell you to move")
319
+ assert "keep everything else in the description" in paragraph
320
+
321
+
322
+ @pytest.mark.parametrize("backend", BACKENDS)
323
+ def test_spec_says_what_to_do_when_the_requester_revises_the_request(backend):
324
+ """TCW-101: the item stays at spec, and the change is recorded where the
325
+ request lives, in either backend's form."""
326
+ paragraph = _paragraph_with(prompt("spec", backend), "The requester revises")
327
+ for words in ("stays at spec", "amendment", "## Added", "`Added` comment"):
328
+ assert words in paragraph, words
329
+
330
+
331
+ def test_plan_says_how_to_file_a_part_into_another_project():
332
+ """TCW-101: --project takes no --parent; the parent is set from inside
333
+ that project, and only then is everything recorded in its version
334
+ control, because the edit itself writes a file there; a ticket key in
335
+ place of a slug means there is no item to edit."""
336
+ paragraph = _paragraph_with(prompt("plan", "filesystem"), "Too large for one item")
337
+ order = [paragraph.index(w) for w in ("--project", "tcw work edit",
338
+ "version control")]
339
+ assert order == sorted(order), paragraph
340
+ assert "ticket key printed instead of a slug" in paragraph
@@ -320,25 +320,25 @@ def test_the_cache_key_is_unchanged():
320
320
  exactly what a shared normalizer would change.
321
321
  """
322
322
  expected = {
323
- ("https://github.com/Proposit-App/proposit-orchestration.git", "main"):
324
- "github.com-proposit-app-proposit-orchestration-73cbcd814e44",
325
- ("https://github.com/Proposit-App/proposit-orchestration", "main"):
326
- "github.com-proposit-app-proposit-orchestration-bc251d728153",
327
- ("git@github.com:Proposit-App/proposit-orchestration.git", "main"):
328
- "github.com-proposit-app-proposit-orchestration-d5bbabd1bdc8",
329
- ("https://github.com/Proposit-App/proposit-orchestration.git", "dev"):
330
- "github.com-proposit-app-proposit-orchestration-447264907fc6",
323
+ ("https://github.com/Example-Org/workspace.git", "main"):
324
+ "github.com-example-org-workspace-ec7917e6e4c3",
325
+ ("https://github.com/Example-Org/workspace", "main"):
326
+ "github.com-example-org-workspace-f86dcb6399fe",
327
+ ("git@github.com:Example-Org/workspace.git", "main"):
328
+ "github.com-example-org-workspace-1a37f0559bb2",
329
+ ("https://github.com/Example-Org/workspace.git", "dev"):
330
+ "github.com-example-org-workspace-c6c86f756591",
331
331
  }
332
332
  for (url, ref), key in expected.items():
333
333
  assert checkouts._cache_key(RepositoryDeclaration(url=url, ref=ref)) == key
334
334
 
335
335
 
336
336
  @pytest.mark.parametrize("spelling", [
337
- "https://github.com/Proposit-App/proposit-orchestration",
338
- "https://github.com/Proposit-App/proposit-orchestration.git",
339
- "https://github.com/Proposit-App/proposit-orchestration/",
340
- " https://github.com/Proposit-App/proposit-orchestration.git ",
341
- "git@github.com:Proposit-App/proposit-orchestration.git",
337
+ "https://github.com/Example-Org/workspace",
338
+ "https://github.com/Example-Org/workspace.git",
339
+ "https://github.com/Example-Org/workspace/",
340
+ " https://github.com/Example-Org/workspace.git ",
341
+ "git@github.com:Example-Org/workspace.git",
342
342
  ])
343
343
  def test_two_spellings_of_one_repository_normalize_alike(spelling):
344
344
  """The question `_cache_key` deliberately answers the other way.
@@ -348,18 +348,18 @@ def test_two_spellings_of_one_repository_normalize_alike(spelling):
348
348
  new resolution rung has to see through that.
349
349
  """
350
350
  canonical = checkouts.normalized_url(
351
- "https://github.com/Proposit-App/proposit-orchestration")
351
+ "https://github.com/Example-Org/workspace")
352
352
  assert checkouts.normalized_url(spelling) == canonical
353
353
 
354
354
 
355
355
  @pytest.mark.parametrize("other", [
356
- "https://github.com/Proposit-App/proposit-core",
357
- "https://github.com/Someone-Else/proposit-orchestration",
358
- "https://gitlab.invalid/Proposit-App/proposit-orchestration",
356
+ "https://github.com/Example-Org/core",
357
+ "https://github.com/Someone-Else/workspace",
358
+ "https://gitlab.invalid/Example-Org/workspace",
359
359
  ])
360
360
  def test_two_different_repositories_do_not_normalize_alike(other):
361
361
  assert checkouts.normalized_url(other) != checkouts.normalized_url(
362
- "https://github.com/Proposit-App/proposit-orchestration")
362
+ "https://github.com/Example-Org/workspace")
363
363
 
364
364
 
365
365
  def test_an_undeclared_component_is_a_no_op(tmp_path):
@@ -90,7 +90,7 @@ def test_the_upstream_does_not_see_its_reader(tmp_path):
90
90
 
91
91
 
92
92
  def test_an_upstream_reached_through_a_parent_is_found(tmp_path):
93
- """The proposit-app shape: a package reaches core through its parent."""
93
+ """The app-repository shape: a package reaches core through its parent."""
94
94
  config(tmp_path / "repo", "id: repo\nprojects:\n children:\n"
95
95
  " pkg: pkg\n upstream:\n core: ../core\n")
96
96
  config(tmp_path / "repo" / "pkg", "id: pkg\nprojects:\n parent:\n"
@@ -545,7 +545,7 @@ def test_an_incomplete_tracker_with_a_parent_does_not(tmp_path):
545
545
  assert "required" in text and _NO_PARENT not in text, text
546
546
 
547
547
 
548
- # ── the Proposit shape, end to end ───────────────────────────────────────────
548
+ # ── the workspace shape, end to end ──────────────────────────────────────────
549
549
 
550
550
  _ROOT_TRACKER = {
551
551
  "provider": "jira-cloud",
@@ -561,33 +561,33 @@ def _edit(node: Path, change) -> None:
561
561
  (node / "tcw-config.yaml").write_text(yaml.safe_dump(cfg, sort_keys=False))
562
562
 
563
563
 
564
- def _proposit(tmp_path: Path) -> dict[str, Path]:
565
- """The shape the request came from: an orchestration root `proposit-app` with
566
- children `proposit-core` and `proposit-app-repo`; a package `shared` below the
564
+ def _workspace(tmp_path: Path) -> dict[str, Path]:
565
+ """The shape the request came from: an orchestration root `product` with
566
+ children `core` and `app-repo`; a package `shared` below the
567
567
  app repository extending core's taxonomy; core's tracker block holding only
568
568
  `candidate-query` and inheriting the rest from the root."""
569
569
  root = tmp_path / "ws"
570
- nodes = {"root": root, "core": root / "proposit-core",
571
- "app": root / "proposit-app",
572
- "shared": root / "proposit-app" / "packages" / "shared"}
573
- for key, pid in (("root", "proposit-app"), ("core", "proposit-core"),
574
- ("app", "proposit-app-repo"), ("shared", "shared")):
570
+ nodes = {"root": root, "core": root / "core",
571
+ "app": root / "app",
572
+ "shared": root / "app" / "packages" / "shared"}
573
+ for key, pid in (("root", "product"), ("core", "core"),
574
+ ("app", "app-repo"), ("shared", "shared")):
575
575
  nodes[key].mkdir(parents=True)
576
576
  if key != "shared": # three repositories, as in the workspace
577
577
  _git(nodes[key], "init", "-q", "-b", "main")
578
578
  init(["taxonomy", "capabilities", "work"], nodes[key], pid)
579
579
  _edit(root, lambda c: c.update({"projects": {"children": {
580
- "proposit-core": "proposit-core", "proposit-app-repo": "proposit-app"}}}))
580
+ "core": "core", "app-repo": "app"}}}))
581
581
  _set_tracker(root, dict(_ROOT_TRACKER))
582
582
  _edit(nodes["core"], lambda c: c.update({"projects": {
583
- "parent": {"proposit-app": ".."}}}))
583
+ "parent": {"product": ".."}}}))
584
584
  _set_tracker(nodes["core"], {"candidate-query": "project = CORE"})
585
585
  _edit(nodes["app"], lambda c: c.update({"projects": {
586
- "parent": {"proposit-app": ".."}, "children": {"shared": "packages/shared"}}}))
586
+ "parent": {"product": ".."}, "children": {"shared": "packages/shared"}}}))
587
587
  _edit(nodes["shared"], lambda c: c.update({"projects": {
588
- "parent": {"proposit-app-repo": "../.."}}}))
588
+ "parent": {"app-repo": "../.."}}}))
589
589
  assert _tcw(nodes["core"], "taxonomy", "add", "Argument").returncode == 0
590
- out = _tcw(nodes["shared"], "taxonomy", "extends", "add", "proposit-core")
590
+ out = _tcw(nodes["shared"], "taxonomy", "extends", "add", "core")
591
591
  assert out.returncode == 0, out.stderr
592
592
  return nodes
593
593
 
@@ -605,16 +605,16 @@ def _assert_state(nodes, *, warned: set[str]) -> None:
605
605
  assert code == 0, (key, text)
606
606
  has_warning = "read as an upstream project" in text
607
607
  assert has_warning == (key in warned), (key, text)
608
- out = _tcw(nodes["shared"], "taxonomy", "show", "proposit-core/argument")
608
+ out = _tcw(nodes["shared"], "taxonomy", "show", "core/argument")
609
609
  assert out.returncode == 0, out.stderr
610
610
 
611
611
 
612
- def test_the_proposit_migration_passes_through_no_blocked_state(tmp_path):
613
- nodes = _proposit(tmp_path)
612
+ def test_the_workspace_migration_passes_through_no_blocked_state(tmp_path):
613
+ nodes = _workspace(tmp_path)
614
614
  _assert_state(nodes, warned=set())
615
615
 
616
616
  step_2 = lambda c: c["projects"].update( # noqa: E731
617
- {"upstream": {"proposit-core": "../proposit-core"}})
617
+ {"upstream": {"core": "../core"}})
618
618
 
619
619
  # The forbidden middle state: step 2 before step 1.
620
620
  _edit(nodes["app"], step_2)
@@ -624,8 +624,8 @@ def test_the_proposit_migration_passes_through_no_blocked_state(tmp_path):
624
624
 
625
625
  # Step 1: the root moves core from children to upstream, one edit.
626
626
  def step_1(c):
627
- c["projects"]["children"].pop("proposit-core")
628
- c["projects"]["upstream"] = {"proposit-core": "proposit-core"}
627
+ c["projects"]["children"].pop("core")
628
+ c["projects"]["upstream"] = {"core": "core"}
629
629
  _edit(nodes["root"], step_1)
630
630
  _assert_state(nodes, warned={"root", "core", "app", "shared"})
631
631
 
@@ -642,7 +642,7 @@ def test_the_proposit_migration_passes_through_no_blocked_state(tmp_path):
642
642
  _edit(nodes["core"], lambda c: c["work"].pop("tracker"))
643
643
  _assert_state(nodes, warned=set())
644
644
  out = _tcw(nodes["core"], "validate")
645
- assert "proposit-app" not in out.stdout + out.stderr, out.stdout
645
+ assert "product" not in out.stdout + out.stderr, out.stdout
646
646
 
647
647
 
648
648
  # ── the CLI's view of an absent upstream, and of what lies beyond one ────────
@@ -1 +0,0 @@
1
- __version__ = "3.0.1"
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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes