jj-stack 0.1.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 (217) hide show
  1. jj_stack-0.1.0/.github/SECURITY.md +20 -0
  2. jj_stack-0.1.0/.github/dependabot.yml +28 -0
  3. jj_stack-0.1.0/.github/workflows/block-pr-base-merges.yml +24 -0
  4. jj_stack-0.1.0/.github/workflows/check-jj-release-updates.yml +24 -0
  5. jj_stack-0.1.0/.github/workflows/ci.yml +95 -0
  6. jj_stack-0.1.0/.github/workflows/codeql.yml +32 -0
  7. jj_stack-0.1.0/.github/workflows/release.yml +149 -0
  8. jj_stack-0.1.0/.gitignore +12 -0
  9. jj_stack-0.1.0/AGENTS.md +96 -0
  10. jj_stack-0.1.0/CLAUDE.md +1 -0
  11. jj_stack-0.1.0/LICENSE +201 -0
  12. jj_stack-0.1.0/NOTICE +2 -0
  13. jj_stack-0.1.0/PKG-INFO +170 -0
  14. jj_stack-0.1.0/README.md +144 -0
  15. jj_stack-0.1.0/check.py +194 -0
  16. jj_stack-0.1.0/complexity-budget.toml +63 -0
  17. jj_stack-0.1.0/docs/AGENTS.md +75 -0
  18. jj_stack-0.1.0/docs/README.md +41 -0
  19. jj_stack-0.1.0/docs/gh-stack.md +38 -0
  20. jj_stack-0.1.0/docs/guides/close-or-separate.md +70 -0
  21. jj_stack-0.1.0/docs/guides/continue-a-stack.md +57 -0
  22. jj_stack-0.1.0/docs/guides/merge-and-sync.md +146 -0
  23. jj_stack-0.1.0/docs/guides/multiple-stacks.md +113 -0
  24. jj_stack-0.1.0/docs/guides/review-a-stack.md +54 -0
  25. jj_stack-0.1.0/docs/guides/revise.md +54 -0
  26. jj_stack-0.1.0/docs/guides/submit-and-update.md +104 -0
  27. jj_stack-0.1.0/docs/guides/working-on-github.md +52 -0
  28. jj_stack-0.1.0/docs/internals/AGENTS.md +30 -0
  29. jj_stack-0.1.0/docs/internals/README.md +22 -0
  30. jj_stack-0.1.0/docs/internals/code-reviews.md +113 -0
  31. jj_stack-0.1.0/docs/internals/design.md +932 -0
  32. jj_stack-0.1.0/docs/internals/implementation-strategy.md +104 -0
  33. jj_stack-0.1.0/docs/internals/property-testing.md +54 -0
  34. jj_stack-0.1.0/docs/internals/releasing.md +47 -0
  35. jj_stack-0.1.0/docs/internals/testing-philosophy.md +97 -0
  36. jj_stack-0.1.0/docs/json-output.schema.json +210 -0
  37. jj_stack-0.1.0/docs/mental-model.md +66 -0
  38. jj_stack-0.1.0/docs/quick-start.md +91 -0
  39. jj_stack-0.1.0/docs/reference/automation.md +133 -0
  40. jj_stack-0.1.0/docs/reference/commands.md +66 -0
  41. jj_stack-0.1.0/docs/reference/configuration.md +66 -0
  42. jj_stack-0.1.0/docs/reference/descriptions.md +59 -0
  43. jj_stack-0.1.0/docs/reference/json-output.md +158 -0
  44. jj_stack-0.1.0/docs/troubleshooting.md +204 -0
  45. jj_stack-0.1.0/evals/jj-stack-skill.md +296 -0
  46. jj_stack-0.1.0/pyproject.toml +90 -0
  47. jj_stack-0.1.0/scripts/README.md +6 -0
  48. jj_stack-0.1.0/scripts/describe_with_claude.py +291 -0
  49. jj_stack-0.1.0/scripts/describe_with_codex.py +303 -0
  50. jj_stack-0.1.0/scripts/describe_with_editor.py +252 -0
  51. jj_stack-0.1.0/scripts/describe_with_prompt.py +146 -0
  52. jj_stack-0.1.0/skills/jj-stack/SKILL.md +146 -0
  53. jj_stack-0.1.0/skills/jj-stack/agents/openai.yaml +4 -0
  54. jj_stack-0.1.0/skills/jj-stack/references/multi-stack.md +84 -0
  55. jj_stack-0.1.0/skills/jj-stack/references/recovery.md +97 -0
  56. jj_stack-0.1.0/src/jj_stack/__init__.py +11 -0
  57. jj_stack-0.1.0/src/jj_stack/__main__.py +8 -0
  58. jj_stack-0.1.0/src/jj_stack/bootstrap.py +213 -0
  59. jj_stack-0.1.0/src/jj_stack/cli.py +1297 -0
  60. jj_stack-0.1.0/src/jj_stack/cli_help.py +680 -0
  61. jj_stack-0.1.0/src/jj_stack/commands/__init__.py +1 -0
  62. jj_stack-0.1.0/src/jj_stack/commands/_cleanup_actions.py +389 -0
  63. jj_stack-0.1.0/src/jj_stack/commands/_json_status.py +84 -0
  64. jj_stack-0.1.0/src/jj_stack/commands/checkout.py +668 -0
  65. jj_stack-0.1.0/src/jj_stack/commands/cleanup/command.py +702 -0
  66. jj_stack-0.1.0/src/jj_stack/commands/cleanup/shared.py +62 -0
  67. jj_stack-0.1.0/src/jj_stack/commands/cleanup/stale.py +79 -0
  68. jj_stack-0.1.0/src/jj_stack/commands/doctor.py +358 -0
  69. jj_stack-0.1.0/src/jj_stack/commands/in_use.py +31 -0
  70. jj_stack-0.1.0/src/jj_stack/commands/list_.py +667 -0
  71. jj_stack-0.1.0/src/jj_stack/commands/merge/__init__.py +1 -0
  72. jj_stack-0.1.0/src/jj_stack/commands/merge/command.py +385 -0
  73. jj_stack-0.1.0/src/jj_stack/commands/merge/github_stack.py +333 -0
  74. jj_stack-0.1.0/src/jj_stack/commands/merge/models.py +97 -0
  75. jj_stack-0.1.0/src/jj_stack/commands/merge/plan.py +109 -0
  76. jj_stack-0.1.0/src/jj_stack/commands/merge/preconditions.py +162 -0
  77. jj_stack-0.1.0/src/jj_stack/commands/merge/render.py +52 -0
  78. jj_stack-0.1.0/src/jj_stack/commands/relink.py +210 -0
  79. jj_stack-0.1.0/src/jj_stack/commands/submit/__init__.py +1 -0
  80. jj_stack-0.1.0/src/jj_stack/commands/submit/auto_close.py +108 -0
  81. jj_stack-0.1.0/src/jj_stack/commands/submit/changes.py +90 -0
  82. jj_stack-0.1.0/src/jj_stack/commands/submit/command.py +780 -0
  83. jj_stack-0.1.0/src/jj_stack/commands/submit/descriptions.py +570 -0
  84. jj_stack-0.1.0/src/jj_stack/commands/submit/github_stack.py +139 -0
  85. jj_stack-0.1.0/src/jj_stack/commands/submit/inputs.py +168 -0
  86. jj_stack-0.1.0/src/jj_stack/commands/submit/models.py +198 -0
  87. jj_stack-0.1.0/src/jj_stack/commands/submit/overview_comments.py +178 -0
  88. jj_stack-0.1.0/src/jj_stack/commands/submit/prs.py +461 -0
  89. jj_stack-0.1.0/src/jj_stack/commands/submit/render.py +129 -0
  90. jj_stack-0.1.0/src/jj_stack/commands/sync.py +510 -0
  91. jj_stack-0.1.0/src/jj_stack/commands/sync_apply.py +474 -0
  92. jj_stack-0.1.0/src/jj_stack/commands/unstack.py +321 -0
  93. jj_stack-0.1.0/src/jj_stack/commands/view.py +1151 -0
  94. jj_stack-0.1.0/src/jj_stack/completion.py +484 -0
  95. jj_stack-0.1.0/src/jj_stack/concurrency.py +93 -0
  96. jj_stack-0.1.0/src/jj_stack/config.py +170 -0
  97. jj_stack-0.1.0/src/jj_stack/console.py +708 -0
  98. jj_stack-0.1.0/src/jj_stack/errors.py +152 -0
  99. jj_stack-0.1.0/src/jj_stack/formatting.py +95 -0
  100. jj_stack-0.1.0/src/jj_stack/github/__init__.py +1 -0
  101. jj_stack-0.1.0/src/jj_stack/github/auth.py +34 -0
  102. jj_stack-0.1.0/src/jj_stack/github/client.py +1098 -0
  103. jj_stack-0.1.0/src/jj_stack/github/error_messages.py +89 -0
  104. jj_stack-0.1.0/src/jj_stack/github/overview_comments.py +35 -0
  105. jj_stack-0.1.0/src/jj_stack/github/pr_refs.py +70 -0
  106. jj_stack-0.1.0/src/jj_stack/github/resolution.py +208 -0
  107. jj_stack-0.1.0/src/jj_stack/github/stack_availability.py +30 -0
  108. jj_stack-0.1.0/src/jj_stack/identifiers.py +7 -0
  109. jj_stack-0.1.0/src/jj_stack/jj/__init__.py +1 -0
  110. jj_stack-0.1.0/src/jj_stack/jj/cli_args.py +23 -0
  111. jj_stack-0.1.0/src/jj_stack/jj/client.py +1459 -0
  112. jj_stack-0.1.0/src/jj_stack/jj/colors.py +199 -0
  113. jj_stack-0.1.0/src/jj_stack/models/__init__.py +1 -0
  114. jj_stack-0.1.0/src/jj_stack/models/git.py +15 -0
  115. jj_stack-0.1.0/src/jj_stack/models/github.py +243 -0
  116. jj_stack-0.1.0/src/jj_stack/models/stack.py +70 -0
  117. jj_stack-0.1.0/src/jj_stack/models/tracking.py +115 -0
  118. jj_stack-0.1.0/src/jj_stack/pr_branch_namespace.py +78 -0
  119. jj_stack-0.1.0/src/jj_stack/stack/__init__.py +1 -0
  120. jj_stack-0.1.0/src/jj_stack/stack/change_status.py +216 -0
  121. jj_stack-0.1.0/src/jj_stack/stack/convergence.py +501 -0
  122. jj_stack-0.1.0/src/jj_stack/stack/convergence_models.py +69 -0
  123. jj_stack-0.1.0/src/jj_stack/stack/convergence_observation.py +162 -0
  124. jj_stack-0.1.0/src/jj_stack/stack/github_stack_safety.py +132 -0
  125. jj_stack-0.1.0/src/jj_stack/stack/global_convergence.py +270 -0
  126. jj_stack-0.1.0/src/jj_stack/stack/path.py +235 -0
  127. jj_stack-0.1.0/src/jj_stack/stack/pr_branches.py +126 -0
  128. jj_stack-0.1.0/src/jj_stack/stack/pr_facts.py +165 -0
  129. jj_stack-0.1.0/src/jj_stack/stack/repo.py +95 -0
  130. jj_stack-0.1.0/src/jj_stack/stack/selected.py +358 -0
  131. jj_stack-0.1.0/src/jj_stack/stack/selection.py +124 -0
  132. jj_stack-0.1.0/src/jj_stack/stack/status.py +711 -0
  133. jj_stack-0.1.0/src/jj_stack/stack/trunk_evidence.py +174 -0
  134. jj_stack-0.1.0/src/jj_stack/state/__init__.py +1 -0
  135. jj_stack-0.1.0/src/jj_stack/state/operation_lock.py +220 -0
  136. jj_stack-0.1.0/src/jj_stack/state/store.py +260 -0
  137. jj_stack-0.1.0/src/jj_stack/ui.py +230 -0
  138. jj_stack-0.1.0/tests/__init__.py +1 -0
  139. jj_stack-0.1.0/tests/conftest.py +50 -0
  140. jj_stack-0.1.0/tests/integration/__init__.py +1 -0
  141. jj_stack-0.1.0/tests/integration/conftest.py +42 -0
  142. jj_stack-0.1.0/tests/integration/submit_command_helpers.py +133 -0
  143. jj_stack-0.1.0/tests/integration/test_boundary_conditions.py +145 -0
  144. jj_stack-0.1.0/tests/integration/test_checkout_command.py +355 -0
  145. jj_stack-0.1.0/tests/integration/test_cleanup_command.py +459 -0
  146. jj_stack-0.1.0/tests/integration/test_doctor_command.py +232 -0
  147. jj_stack-0.1.0/tests/integration/test_jj_stack.py +408 -0
  148. jj_stack-0.1.0/tests/integration/test_list_command.py +449 -0
  149. jj_stack-0.1.0/tests/integration/test_merge_command.py +566 -0
  150. jj_stack-0.1.0/tests/integration/test_relink_command.py +179 -0
  151. jj_stack-0.1.0/tests/integration/test_submit_command.py +2415 -0
  152. jj_stack-0.1.0/tests/integration/test_sync_command.py +1041 -0
  153. jj_stack-0.1.0/tests/integration/test_unstack_command.py +198 -0
  154. jj_stack-0.1.0/tests/integration/test_view_command.py +554 -0
  155. jj_stack-0.1.0/tests/property/test_submit_property_scenarios.py +343 -0
  156. jj_stack-0.1.0/tests/run_live_github.py +589 -0
  157. jj_stack-0.1.0/tests/run_submit_property_scenarios.py +240 -0
  158. jj_stack-0.1.0/tests/support/__init__.py +1 -0
  159. jj_stack-0.1.0/tests/support/change_helpers.py +18 -0
  160. jj_stack-0.1.0/tests/support/fake_github.py +1736 -0
  161. jj_stack-0.1.0/tests/support/integration_helpers.py +429 -0
  162. jj_stack-0.1.0/tests/support/json_schema.py +50 -0
  163. jj_stack-0.1.0/tests/support/output_assertions.py +27 -0
  164. jj_stack-0.1.0/tests/support/pytest_concurrency.py +372 -0
  165. jj_stack-0.1.0/tests/support/stack_edit_scenarios.py +140 -0
  166. jj_stack-0.1.0/tests/support/submit_property_harness.py +1180 -0
  167. jj_stack-0.1.0/tests/support/submit_property_scenarios.py +1144 -0
  168. jj_stack-0.1.0/tests/support/tracking.py +24 -0
  169. jj_stack-0.1.0/tests/unit/__init__.py +1 -0
  170. jj_stack-0.1.0/tests/unit/entrypoint_test_helpers.py +37 -0
  171. jj_stack-0.1.0/tests/unit/test_bootstrap.py +113 -0
  172. jj_stack-0.1.0/tests/unit/test_change_status.py +96 -0
  173. jj_stack-0.1.0/tests/unit/test_change_status_topology.py +123 -0
  174. jj_stack-0.1.0/tests/unit/test_check_script.py +188 -0
  175. jj_stack-0.1.0/tests/unit/test_checkout.py +22 -0
  176. jj_stack-0.1.0/tests/unit/test_cleanup.py +218 -0
  177. jj_stack-0.1.0/tests/unit/test_cli.py +301 -0
  178. jj_stack-0.1.0/tests/unit/test_cli_dispatch.py +99 -0
  179. jj_stack-0.1.0/tests/unit/test_completion.py +89 -0
  180. jj_stack-0.1.0/tests/unit/test_concurrency.py +65 -0
  181. jj_stack-0.1.0/tests/unit/test_config.py +172 -0
  182. jj_stack-0.1.0/tests/unit/test_describe_with_editor_script.py +121 -0
  183. jj_stack-0.1.0/tests/unit/test_describe_with_prompt_script.py +67 -0
  184. jj_stack-0.1.0/tests/unit/test_errors.py +86 -0
  185. jj_stack-0.1.0/tests/unit/test_github_auth.py +38 -0
  186. jj_stack-0.1.0/tests/unit/test_github_client.py +596 -0
  187. jj_stack-0.1.0/tests/unit/test_github_models.py +67 -0
  188. jj_stack-0.1.0/tests/unit/test_github_resolution.py +170 -0
  189. jj_stack-0.1.0/tests/unit/test_github_stack_planning.py +152 -0
  190. jj_stack-0.1.0/tests/unit/test_in_use_command.py +76 -0
  191. jj_stack-0.1.0/tests/unit/test_jj_client.py +889 -0
  192. jj_stack-0.1.0/tests/unit/test_list.py +25 -0
  193. jj_stack-0.1.0/tests/unit/test_live_github_runner.py +45 -0
  194. jj_stack-0.1.0/tests/unit/test_merge.py +167 -0
  195. jj_stack-0.1.0/tests/unit/test_operation_lock.py +108 -0
  196. jj_stack-0.1.0/tests/unit/test_pr_branches.py +140 -0
  197. jj_stack-0.1.0/tests/unit/test_pr_refs.py +51 -0
  198. jj_stack-0.1.0/tests/unit/test_property_runner.py +50 -0
  199. jj_stack-0.1.0/tests/unit/test_property_scenarios.py +54 -0
  200. jj_stack-0.1.0/tests/unit/test_relink.py +93 -0
  201. jj_stack-0.1.0/tests/unit/test_selection.py +24 -0
  202. jj_stack-0.1.0/tests/unit/test_stack_path.py +231 -0
  203. jj_stack-0.1.0/tests/unit/test_stack_status.py +347 -0
  204. jj_stack-0.1.0/tests/unit/test_store.py +158 -0
  205. jj_stack-0.1.0/tests/unit/test_submit.py +353 -0
  206. jj_stack-0.1.0/tests/unit/test_submit_descriptions.py +271 -0
  207. jj_stack-0.1.0/tests/unit/test_sync.py +19 -0
  208. jj_stack-0.1.0/tests/unit/test_trunk_evidence.py +186 -0
  209. jj_stack-0.1.0/tests/unit/test_ui.py +216 -0
  210. jj_stack-0.1.0/tests/unit/test_unstack.py +30 -0
  211. jj_stack-0.1.0/tests/unit/test_view.py +367 -0
  212. jj_stack-0.1.0/tests/unit/test_view_entrypoint.py +245 -0
  213. jj_stack-0.1.0/tools/check_complexity.py +215 -0
  214. jj_stack-0.1.0/tools/check_jj_release_updates.py +188 -0
  215. jj_stack-0.1.0/tools/check_release_artifacts.py +118 -0
  216. jj_stack-0.1.0/tools/install-jj-release.sh +266 -0
  217. jj_stack-0.1.0/uv.lock +585 -0
@@ -0,0 +1,20 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ This project is under active development. Security fixes are supported on `main`.
6
+
7
+ ## Reporting a Vulnerability
8
+
9
+ Please do not report security vulnerabilities in public GitHub issues.
10
+
11
+ Use GitHub's private vulnerability reporting for this repo if it is enabled. If you cannot
12
+ use private reporting, contact the maintainers directly and include:
13
+
14
+ - a description of the issue
15
+ - steps to reproduce or a proof of concept
16
+ - the affected version or environment details
17
+ - any suggested mitigations or fixes you have identified
18
+
19
+ We will investigate reports on a best-effort basis and coordinate on disclosure before any public
20
+ announcement.
@@ -0,0 +1,28 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ cooldown:
8
+ default-days: 7
9
+ groups:
10
+ github-actions:
11
+ patterns:
12
+ - "*"
13
+ commit-message:
14
+ prefix: "ci"
15
+
16
+ - package-ecosystem: "uv"
17
+ directory: "/"
18
+ schedule:
19
+ interval: "weekly"
20
+ cooldown:
21
+ default-days: 7
22
+ groups:
23
+ python-dependencies:
24
+ patterns:
25
+ - "*"
26
+ versioning-strategy: "increase-if-necessary"
27
+ commit-message:
28
+ prefix: "deps"
@@ -0,0 +1,24 @@
1
+ name: block-pr-base-merges
2
+
3
+ on:
4
+ pull_request_target:
5
+ branches:
6
+ - "jj-stack/**"
7
+ types:
8
+ - opened
9
+ - reopened
10
+ - synchronize
11
+ - edited
12
+ - ready_for_review
13
+
14
+ jobs:
15
+ reject-pr-base-merge:
16
+ name: reject-pr-base-merge
17
+ runs-on: ubuntu-latest
18
+ permissions: {}
19
+ steps:
20
+ - name: Explain policy and fail
21
+ run: |
22
+ echo "PRs targeting jj-stack/* are based on another PR and must not be merged directly."
23
+ echo "Retarget this PR to main or another allowed base branch."
24
+ exit 1
@@ -0,0 +1,24 @@
1
+ name: check jj release updates
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "23 7 * * 1"
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+ issues: write
11
+
12
+ jobs:
13
+ check-jj-release-updates:
14
+ runs-on: ubuntu-latest
15
+
16
+ steps:
17
+ - name: Check out repo
18
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
19
+
20
+ - name: Check tested jj versions against the latest release
21
+ env:
22
+ GITHUB_TOKEN: ${{ github.token }}
23
+ REPOSITORY: ${{ github.repository }}
24
+ run: python tools/check_jj_release_updates.py --write-issues
@@ -0,0 +1,95 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ complexity:
14
+ runs-on: ubuntu-latest
15
+
16
+ steps:
17
+ - name: Check out repo
18
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
19
+
20
+ - name: Set up uv
21
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
22
+ with:
23
+ python-version: "3.14"
24
+
25
+ - name: Install tokei
26
+ env:
27
+ # Must match TOKEI_VERSION in tools/check_complexity.py; the budgets are baselined
28
+ # against this exact counter. 14.0.0 publishes no prebuilt binaries, so build it.
29
+ TOKEI_VERSION: 14.0.0
30
+ run: cargo install tokei --locked --version "$TOKEI_VERSION"
31
+
32
+ - name: Install project environment
33
+ run: uv sync --locked
34
+
35
+ - name: Enforce complexity budgets
36
+ run: uv run tools/check_complexity.py
37
+
38
+ check:
39
+ strategy:
40
+ fail-fast: false
41
+ matrix:
42
+ jj-version: ["v0.44.0"]
43
+ os: [ubuntu-latest, macos-latest, windows-latest]
44
+ python-version: ["3.14"]
45
+ runs-on: ${{ matrix.os }}
46
+ env:
47
+ JJ_VERSION: ${{ matrix.jj-version }}
48
+
49
+ steps:
50
+ - name: Check out repo
51
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
52
+
53
+ - name: Set up uv
54
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
55
+ with:
56
+ python-version: ${{ matrix.python-version }}
57
+
58
+ - name: Install jj
59
+ shell: bash
60
+ run: |
61
+ install_dir="$(tools/install-jj-release.sh "$JJ_VERSION")"
62
+ if command -v cygpath >/dev/null 2>&1; then
63
+ install_dir="$(cygpath -w "$install_dir")"
64
+ fi
65
+ printf '%s\n' "$install_dir" >> "$GITHUB_PATH"
66
+
67
+ - name: Run local verification suite
68
+ shell: bash
69
+ run: ./check.py
70
+
71
+ submit-property-smoke:
72
+ runs-on: ubuntu-latest
73
+ env:
74
+ JJ_VERSION: v0.44.0
75
+
76
+ steps:
77
+ - name: Check out repo
78
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
79
+
80
+ - name: Set up uv
81
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
82
+ with:
83
+ python-version: "3.14"
84
+
85
+ - name: Install jj
86
+ run: echo "$(tools/install-jj-release.sh "$JJ_VERSION")" >> "$GITHUB_PATH"
87
+
88
+ - name: Run submit property smoke scenarios
89
+ run: >-
90
+ tests/run_submit_property_scenarios.py 10 --random-seed -n auto
91
+ --stack-join-scenarios 5
92
+ --lifecycle-scenarios 10
93
+ --stack-move-scenarios 5
94
+ --retry-scenarios 5
95
+ --drift-scenarios 21
@@ -0,0 +1,32 @@
1
+ name: codeql
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ schedule:
9
+ - cron: "31 7 * * 1"
10
+
11
+ permissions:
12
+ actions: read
13
+ contents: read
14
+ security-events: write
15
+
16
+ jobs:
17
+ analyze:
18
+ name: analyze
19
+ runs-on: ubuntu-latest
20
+
21
+ steps:
22
+ - name: Check out repo
23
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
24
+
25
+ - name: Initialize CodeQL
26
+ uses: github/codeql-action/init@v4.37.3
27
+ with:
28
+ languages: python
29
+ build-mode: none
30
+
31
+ - name: Analyze
32
+ uses: github/codeql-action/analyze@v4.37.3
@@ -0,0 +1,149 @@
1
+ name: release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: release-${{ github.ref }}
14
+ cancel-in-progress: false
15
+
16
+ env:
17
+ JJ_VERSION: v0.44.0
18
+
19
+ jobs:
20
+ build:
21
+ runs-on: ubuntu-latest
22
+ timeout-minutes: 30
23
+
24
+ steps:
25
+ - name: Check out repo
26
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
27
+ with:
28
+ fetch-depth: 0
29
+
30
+ - name: Set up uv
31
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
32
+ with:
33
+ python-version: "3.14"
34
+
35
+ - name: Verify tag matches package version
36
+ if: startsWith(github.ref, 'refs/tags/v')
37
+ env:
38
+ RELEASE_TAG: ${{ github.ref_name }}
39
+ run: test "$RELEASE_TAG" = "v$(uv version --short)"
40
+
41
+ - name: Verify tagged commit is on main
42
+ if: startsWith(github.ref, 'refs/tags/v')
43
+ run: git merge-base --is-ancestor HEAD refs/remotes/origin/main
44
+
45
+ - name: Install jj
46
+ run: echo "$(tools/install-jj-release.sh "$JJ_VERSION")" >> "$GITHUB_PATH"
47
+
48
+ - name: Run local verification suite
49
+ run: ./check.py
50
+
51
+ - name: Build distributions
52
+ run: uv build
53
+
54
+ - name: Test built distributions
55
+ run: python tools/check_release_artifacts.py
56
+
57
+ - name: Upload distributions
58
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
59
+ with:
60
+ name: dist
61
+ path: dist/*
62
+ if-no-files-found: error
63
+ retention-days: 7
64
+
65
+ publish-testpypi:
66
+ if: github.event_name == 'workflow_dispatch'
67
+ needs: build
68
+ runs-on: ubuntu-latest
69
+ timeout-minutes: 10
70
+ permissions:
71
+ contents: read
72
+ id-token: write
73
+ environment:
74
+ name: testpypi
75
+
76
+ steps:
77
+ - name: Set up uv
78
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
79
+ with:
80
+ python-version: "3.14"
81
+
82
+ - name: Download distributions
83
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
84
+ with:
85
+ name: dist
86
+ path: dist
87
+
88
+ - name: Publish to TestPyPI
89
+ run: >
90
+ uv publish
91
+ --trusted-publishing always
92
+ --publish-url https://test.pypi.org/legacy/
93
+ --check-url https://test.pypi.org/simple/
94
+ dist/*
95
+
96
+ publish-pypi:
97
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
98
+ needs: build
99
+ runs-on: ubuntu-latest
100
+ timeout-minutes: 10
101
+ permissions:
102
+ contents: read
103
+ id-token: write
104
+ environment:
105
+ name: pypi
106
+
107
+ steps:
108
+ - name: Set up uv
109
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
110
+ with:
111
+ python-version: "3.14"
112
+
113
+ - name: Download distributions
114
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
115
+ with:
116
+ name: dist
117
+ path: dist
118
+
119
+ - name: Publish to PyPI
120
+ run: >
121
+ uv publish
122
+ --trusted-publishing always
123
+ --check-url https://pypi.org/simple/
124
+ dist/*
125
+
126
+ publish-github-release:
127
+ needs: publish-pypi
128
+ runs-on: ubuntu-latest
129
+ timeout-minutes: 5
130
+ permissions:
131
+ contents: write
132
+
133
+ steps:
134
+ - name: Download distributions
135
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
136
+ with:
137
+ name: dist
138
+ path: dist
139
+
140
+ - name: Publish GitHub release
141
+ env:
142
+ GH_TOKEN: ${{ github.token }}
143
+ RELEASE_TAG: ${{ github.ref_name }}
144
+ run: |
145
+ if ! gh release view "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
146
+ gh release create "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" --verify-tag \
147
+ --generate-notes --title "$RELEASE_TAG"
148
+ fi
149
+ gh release upload "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" --clobber dist/*
@@ -0,0 +1,12 @@
1
+ __pycache__/
2
+ .coverage
3
+ .claude/
4
+ htmlcov/
5
+ .pytest_cache/
6
+ .roam/
7
+ .ruff_cache/
8
+ .tmp/
9
+ .ty_cache/
10
+ .uv-cache/
11
+ .venv
12
+ .venv/
@@ -0,0 +1,96 @@
1
+ # Work in progress
2
+
3
+ This project is under heavy development. Do not make any attempt to write backwards
4
+ compatibility code, migration code, or the like.
5
+
6
+ ## Complexity control
7
+
8
+ - A replacement is incomplete until it deletes the mechanism it supersedes in the same change.
9
+ Do not add a temporary parallel model with a promise to remove it in a later cleanup slice.
10
+ - Define each jj-stack-owned durable policy fact once and store it one way. Shared observation or
11
+ storage code must not create a second path for deciding or changing it.
12
+ - Batch independent read-only facts, but keep dependent mutations in order. Bind an irreversible
13
+ external mutation to the identity and version observed while planning when the platform
14
+ supports a conditional write or lease. Re-observe only when an earlier mutation invalidates a
15
+ precondition or when an observed trigger or platform contract requires it.
16
+ - Apply the cumulative complexity budgets after every code slice. CI runs
17
+ `uv run tools/check_complexity.py`; run it locally when the pinned `tokei` is installed. A
18
+ budget increase is a design stop that requires explicit review, not routine maintenance of the
19
+ budget file.
20
+ - If the same subsystem needs a third consecutive hardening change, stop patching it and
21
+ re-derive the design from the core invariants.
22
+
23
+ # Workflow
24
+
25
+ - This is a `jj` repo. Do not use `git` to work on the repo itself.
26
+ - Do not use git worktree-based agent isolation in this repo. For isolated parallel work, use
27
+ `jj workspace` instead.
28
+ - Run the CLI locally with `uv run jj-stack ...` instead of invoking the module or virtualenv
29
+ path directly.
30
+ - Hard-wrap code and markdown files at 98 columns unless a file uses a different convention.
31
+
32
+ # Commit messages
33
+
34
+ - Format the first line as a concise scoped subject, usually `scope: summary`.
35
+ - Match the repo's existing subject style: use a lowercase scope such as `status`, `docs`, or
36
+ `cli`, followed by a short lowercase phrase, with no trailing period.
37
+ - Use a body for any change whose purpose is not obvious from the subject and diff.
38
+ - Hard-wrap commit message bodies at 72 columns.
39
+ - The body should explain the motivation for the change, the intended behavior or design outcome,
40
+ and any important scope or design constraints.
41
+ - Do not use the body to narrate the code or to record routine validation such as `./check.py`.
42
+ - Prefer explaining why the commit exists and what rule or user-visible behavior it is enforcing.
43
+
44
+ # Documentation
45
+
46
+ - User-facing docs live in `docs/`. See [docs/AGENTS.md](docs/AGENTS.md) for the vocabulary
47
+ rules and the public/internal split. Built-in `--help` text is held to the same standard as
48
+ the user docs: assume jj/git familiarity, avoid `jj-stack` internal design jargon.
49
+ - The web version of the user docs normally lives in the sibling jj repository at
50
+ `$(jj root)/../website`. When user-facing docs change here, inspect and update the corresponding
51
+ web docs there too when needed. If the change here is committed, commit the corresponding
52
+ website update in that repository as well; preserve unrelated work in either working copy.
53
+ - Active internal docs use ordinary technical language too. Introduce a project-specific term
54
+ only when it names a real type, field, or enduring rule, define it at first use, and prefer
55
+ describing concrete inputs and effects.
56
+ - `design.md` and `implementation-strategy.md` describe the current product and architecture, not
57
+ completed slices or abandoned mechanisms. Keep implementation history in `jj` commits.
58
+ - Default to code and tests only. Update documentation only when a change intentionally adds or
59
+ changes a supported product rule or user workflow, or makes a specific existing statement
60
+ materially inaccurate. A bug and its fix are not by themselves a documentation trigger.
61
+ - When documentation is required, update only the affected source: `design.md` for an enduring
62
+ product rule, user docs or `--help` for user guidance, and `implementation-strategy.md` for an
63
+ architecture, tooling, or test-layer strategy change.
64
+
65
+ # Behaviour changes
66
+
67
+ - In user-facing output, identify revisions by `change_id` by default. If a concrete immutable
68
+ snapshot matters, include the `commit_id` second and label it explicitly.
69
+ - Read [docs/internals/design.md](docs/internals/design.md) before intentionally changing product
70
+ semantics or adding tests for product behavior. Design prose is derived from principles, not
71
+ the other way around: evaluate a documented behavior on its merits before extending it, and
72
+ prefer deleting case-specific rules that follow from the principles over adding new ones. Never
73
+ add durable transaction or replay state; recovery is observational (see design.md).
74
+ - Preserve the core invariants: the `jj` DAG determines stack topology, local cache is sparse,
75
+ GitHub pull requests are derived from the local `jj` stack, and ambiguous linkage fails closed.
76
+
77
+ # Testing
78
+
79
+ - Run `./check.py` before finishing a code change. Docs-only edits under `docs/` do not require
80
+ a test run.
81
+ - Run `./check.py` for the default local Ruff, type-check, and test pass before finishing a
82
+ code change.
83
+ - For focused test runs, do not use plain `uv run pytest ...`; it can miss the repo's package
84
+ path in this project layout. First run `uv sync --locked`, then invoke pytest through the repo
85
+ virtualenv, for example `.venv/bin/python -m pytest tests/unit/test_jj_client.py`.
86
+ - Before adding, modifying, removing, or reviewing tests, fixtures, helpers, or property
87
+ scenarios, read and follow
88
+ [docs/internals/testing-philosophy.md](docs/internals/testing-philosophy.md). Add or retain
89
+ coverage only for a distinct worthwhile risk at the narrowest meaningful layer; search for and
90
+ consolidate overlapping coverage first. For property-harness changes, also follow
91
+ [docs/internals/property-testing.md](docs/internals/property-testing.md).
92
+
93
+ # Code reviews
94
+
95
+ - When reviewing changes or existing code, read and follow
96
+ [docs/internals/code-reviews.md](docs/internals/code-reviews.md).
@@ -0,0 +1 @@
1
+ @AGENTS.md