netbox-super-cli 1.7.0__tar.gz → 1.8.1__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 (370) hide show
  1. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/workflows/bench.yml +2 -2
  2. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/workflows/claude.yml +2 -2
  3. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/workflows/docs.yml +4 -4
  4. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/workflows/e2e.yml +37 -2
  5. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/workflows/lint.yml +6 -6
  6. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/workflows/release.yml +3 -3
  7. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/workflows/test.yml +2 -2
  8. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.pre-commit-config.yaml +1 -0
  9. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/AGENTS.md +1 -0
  10. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/CHANGELOG.md +109 -0
  11. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/CLAUDE.md +1 -0
  12. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/PKG-INFO +22 -1
  13. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/README.md +20 -0
  14. netbox_super_cli-1.8.1/SECURITY.md +12 -0
  15. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/architecture/http-client.md +9 -0
  16. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/architecture/overview.md +1 -0
  17. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/getting-started/concepts.md +16 -0
  18. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/getting-started/first-run.md +6 -2
  19. netbox_super_cli-1.8.1/docs/guides/branching.md +140 -0
  20. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/guides/ci-and-automation.md +17 -0
  21. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/guides/interactive-tui.md +16 -0
  22. netbox_super_cli-1.8.1/docs/guides/keyring.md +86 -0
  23. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/guides/managing-profiles.md +29 -6
  24. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/guides/output-formats.md +5 -0
  25. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/guides/using-with-ai-agents.md +1 -0
  26. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/guides/working-with-plugins.md +11 -0
  27. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/guides/writes-and-safety.md +17 -0
  28. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/index.md +3 -0
  29. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/reference/config.md +2 -1
  30. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/justfile +10 -0
  31. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/mkdocs.yml +2 -0
  32. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/_version.py +1 -1
  33. netbox_super_cli-1.8.1/nsc/auth/keyring_store.py +77 -0
  34. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/auth/verify.py +71 -25
  35. netbox_super_cli-1.8.1/nsc/branching/__init__.py +5 -0
  36. netbox_super_cli-1.8.1/nsc/branching/api.py +100 -0
  37. netbox_super_cli-1.8.1/nsc/branching/errors.py +82 -0
  38. netbox_super_cli-1.8.1/nsc/branching/jobs.py +57 -0
  39. netbox_super_cli-1.8.1/nsc/branching/models.py +42 -0
  40. netbox_super_cli-1.8.1/nsc/branching/resolve.py +46 -0
  41. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/aliases_commands.py +4 -3
  42. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/app.py +49 -3
  43. netbox_super_cli-1.8.1/nsc/cli/branch_commands.py +460 -0
  44. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/cache_commands.py +4 -2
  45. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/globals.py +15 -0
  46. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/handlers.py +23 -9
  47. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/login_commands.py +153 -25
  48. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/profiles_commands.py +2 -2
  49. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/registration.py +12 -5
  50. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/runtime.py +105 -8
  51. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/tui_commands.py +19 -1
  52. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/config/loader.py +11 -1
  53. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/config/models.py +31 -2
  54. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/config/writer.py +6 -1
  55. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/http/client.py +48 -28
  56. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/http/errors.py +4 -0
  57. netbox_super_cli-1.8.1/nsc/http/pagination.py +78 -0
  58. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/__init__.py +2 -0
  59. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/app.py +6 -0
  60. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/keymap.py +1 -0
  61. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/list.py +104 -7
  62. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/styles.tcss +6 -0
  63. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/view.py +11 -0
  64. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/pyproject.toml +4 -1
  65. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/skills/netbox-super-cli/SKILL.md +31 -1
  66. netbox_super_cli-1.8.1/tests/auth/test_keyring_store.py +58 -0
  67. netbox_super_cli-1.8.1/tests/auth/test_verify.py +283 -0
  68. netbox_super_cli-1.8.1/tests/branching/_fixtures.py +54 -0
  69. netbox_super_cli-1.8.1/tests/branching/test_api.py +159 -0
  70. netbox_super_cli-1.8.1/tests/branching/test_jobs.py +70 -0
  71. netbox_super_cli-1.8.1/tests/branching/test_resolve.py +106 -0
  72. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_aliases_commands.py +15 -0
  73. netbox_super_cli-1.8.1/tests/cli/test_branch_commands.py +291 -0
  74. netbox_super_cli-1.8.1/tests/cli/test_branch_lifecycle.py +179 -0
  75. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_cache_commands.py +31 -0
  76. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_handlers.py +72 -0
  77. netbox_super_cli-1.8.1/tests/cli/test_lazy_keyring_import.py +27 -0
  78. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_login_commands.py +26 -0
  79. netbox_super_cli-1.8.1/tests/cli/test_login_keyring.py +528 -0
  80. netbox_super_cli-1.8.1/tests/cli/test_runtime_branch.py +157 -0
  81. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_tui_command.py +2 -0
  82. netbox_super_cli-1.8.1/tests/config/test_keyring_tag.py +67 -0
  83. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/config/test_models.py +6 -0
  84. netbox_super_cli-1.8.1/tests/conftest.py +85 -0
  85. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/README.md +12 -0
  86. netbox_super_cli-1.8.1/tests/e2e/branching/Dockerfile +5 -0
  87. netbox_super_cli-1.8.1/tests/e2e/branching/plugins.py +21 -0
  88. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/conftest.py +8 -0
  89. netbox_super_cli-1.8.1/tests/e2e/docker-compose.branching.yml +45 -0
  90. netbox_super_cli-1.8.1/tests/e2e/test_branching.py +137 -0
  91. netbox_super_cli-1.8.1/tests/e2e/test_keyring_roundtrip.py +79 -0
  92. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/test_login.py +53 -2
  93. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/http/test_client.py +53 -0
  94. netbox_super_cli-1.8.1/tests/http/test_client_branch.py +112 -0
  95. netbox_super_cli-1.8.1/tests/http/test_pagination.py +127 -0
  96. netbox_super_cli-1.8.1/tests/tui/__init__.py +0 -0
  97. netbox_super_cli-1.8.1/tests/tui/test_branch_indicator.py +24 -0
  98. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_list_screen.py +298 -0
  99. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_view.py +17 -1
  100. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/uv.lock +234 -23
  101. netbox_super_cli-1.7.0/tests/auth/test_verify.py +0 -70
  102. netbox_super_cli-1.7.0/tests/conftest.py +0 -41
  103. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  104. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  105. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/ISSUE_TEMPLATE/docs.yml +0 -0
  106. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  107. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/dependabot.yml +0 -0
  108. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/pull_request_template.md +0 -0
  109. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/workflows/skill-convention-review.yml +0 -0
  110. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.gitignore +0 -0
  111. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.python-version +0 -0
  112. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/LICENSE +0 -0
  113. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/architecture/caching.md +0 -0
  114. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/architecture/command-generation.md +0 -0
  115. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/architecture/schema-loading.md +0 -0
  116. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/assets/tui/detail.svg +0 -0
  117. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/assets/tui/filter.svg +0 -0
  118. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/assets/tui/list.svg +0 -0
  119. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/assets/tui/picker.svg +0 -0
  120. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/assets/tui/search.svg +0 -0
  121. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/contributing/adding-bundled-schemas.md +0 -0
  122. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/contributing/branching.md +0 -0
  123. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/contributing/development.md +0 -0
  124. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/contributing/release-process.md +0 -0
  125. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/getting-started/install.md +0 -0
  126. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/guides/audit-log.md +0 -0
  127. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/reference/cli.md +0 -0
  128. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/reference/exit-codes.md +0 -0
  129. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/reference/schemas.md +0 -0
  130. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/__init__.py +0 -0
  131. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/__main__.py +0 -0
  132. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/aliases/__init__.py +0 -0
  133. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/aliases/resolver.py +0 -0
  134. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/auth/__init__.py +0 -0
  135. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/builder/__init__.py +0 -0
  136. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/builder/build.py +0 -0
  137. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cache/__init__.py +0 -0
  138. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cache/store.py +0 -0
  139. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/__init__.py +0 -0
  140. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/commands_dump.py +0 -0
  141. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/config_commands.py +0 -0
  142. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/init_commands.py +0 -0
  143. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/skill_commands.py +0 -0
  144. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/writes/__init__.py +0 -0
  145. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/writes/apply.py +0 -0
  146. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/writes/bulk.py +0 -0
  147. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/writes/coercion.py +0 -0
  148. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/writes/confirmation.py +0 -0
  149. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/writes/input.py +0 -0
  150. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/writes/preflight.py +0 -0
  151. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/completion/__init__.py +0 -0
  152. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/completion/cache_probe.py +0 -0
  153. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/completion/callbacks.py +0 -0
  154. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/completion/providers.py +0 -0
  155. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/config/__init__.py +0 -0
  156. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/config/saved_searches.py +0 -0
  157. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/config/settings.py +0 -0
  158. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/http/__init__.py +0 -0
  159. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/http/audit.py +0 -0
  160. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/http/retry.py +0 -0
  161. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/model/__init__.py +0 -0
  162. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/model/command_model.py +0 -0
  163. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/__init__.py +0 -0
  164. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/_console.py +0 -0
  165. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/colors.py +0 -0
  166. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/csv_.py +0 -0
  167. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/errors.py +0 -0
  168. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/explain.py +0 -0
  169. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/flatten.py +0 -0
  170. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/headers.py +0 -0
  171. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/json_.py +0 -0
  172. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/jsonl.py +0 -0
  173. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/render.py +0 -0
  174. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/table.py +0 -0
  175. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/yaml_.py +0 -0
  176. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/savedfilters/__init__.py +0 -0
  177. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/savedfilters/custom_fields.py +0 -0
  178. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/savedfilters/objecttypes.py +0 -0
  179. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/savedfilters/params.py +0 -0
  180. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/savedfilters/store.py +0 -0
  181. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/savedfilters/tags.py +0 -0
  182. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schema/__init__.py +0 -0
  183. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schema/hashing.py +0 -0
  184. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schema/loader.py +0 -0
  185. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schema/models.py +0 -0
  186. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schema/source.py +0 -0
  187. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schemas/__init__.py +0 -0
  188. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schemas/bundled/__init__.py +0 -0
  189. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schemas/bundled/manifest.yaml +0 -0
  190. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schemas/bundled/netbox-4.5.10.json.gz +0 -0
  191. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schemas/bundled/netbox-4.6.0.json.gz +0 -0
  192. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/skill/__init__.py +0 -0
  193. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/_bindings.py +0 -0
  194. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/bulk.py +0 -0
  195. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/catalog.py +0 -0
  196. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/columns.py +0 -0
  197. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/errors.py +0 -0
  198. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/filters.py +0 -0
  199. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/fk.py +0 -0
  200. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/forms.py +0 -0
  201. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/nav.py +0 -0
  202. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/relations.py +0 -0
  203. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/__init__.py +0 -0
  204. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/bulk_edit_form.py +0 -0
  205. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/columns.py +0 -0
  206. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/detail.py +0 -0
  207. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/edit_form.py +0 -0
  208. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/filter.py +0 -0
  209. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/global_search.py +0 -0
  210. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/picker.py +0 -0
  211. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/record_picker.py +0 -0
  212. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/saved_search_picker.py +0 -0
  213. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/search.py +0 -0
  214. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/selection.py +0 -0
  215. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/widgets/__init__.py +0 -0
  216. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/widgets/_modal.py +0 -0
  217. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/widgets/bulk_diff.py +0 -0
  218. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/widgets/bulk_summary.py +0 -0
  219. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/widgets/confirm.py +0 -0
  220. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/widgets/diff.py +0 -0
  221. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/widgets/help.py +0 -0
  222. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/widgets/nav_tree.py +0 -0
  223. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/scripts/gen_docs.py +0 -0
  224. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/scripts/sync_agents_md.py +0 -0
  225. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/__init__.py +0 -0
  226. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/aliases/__init__.py +0 -0
  227. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/aliases/test_resolver.py +0 -0
  228. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/audit/__init__.py +0 -0
  229. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/audit/test_redaction_full.py +0 -0
  230. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/auth/__init__.py +0 -0
  231. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/benchmarks/__init__.py +0 -0
  232. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/benchmarks/test_startup.py +0 -0
  233. {netbox_super_cli-1.7.0/tests/builder → netbox_super_cli-1.8.1/tests/branching}/__init__.py +0 -0
  234. {netbox_super_cli-1.7.0/tests/cache → netbox_super_cli-1.8.1/tests/builder}/__init__.py +0 -0
  235. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/builder/test_build.py +0 -0
  236. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/builder/test_default_columns.py +0 -0
  237. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/builder/test_fk_metadata.py +0 -0
  238. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/builder/test_redaction_marking.py +0 -0
  239. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/builder/test_request_body_shape.py +0 -0
  240. {netbox_super_cli-1.7.0/tests/cli → netbox_super_cli-1.8.1/tests/cache}/__init__.py +0 -0
  241. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cache/test_prune.py +0 -0
  242. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cache/test_store.py +0 -0
  243. {netbox_super_cli-1.7.0/tests/cli/writes → netbox_super_cli-1.8.1/tests/cli}/__init__.py +0 -0
  244. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_app_smoke.py +0 -0
  245. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_commands_dump.py +0 -0
  246. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_completion_protocol_smoke.py +0 -0
  247. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_completion_smoke.py +0 -0
  248. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_config_commands.py +0 -0
  249. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_dynamic_completion.py +0 -0
  250. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_explain.py +0 -0
  251. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_globals_color.py +0 -0
  252. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_init_commands.py +0 -0
  253. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_lazy_httpx2_import.py +0 -0
  254. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_lazy_textual_import.py +0 -0
  255. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_meta_subcommands_under_broken_config.py +0 -0
  256. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_ndjson_input.py +0 -0
  257. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_profiles_commands.py +0 -0
  258. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_registration.py +0 -0
  259. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_respx_integration.py +0 -0
  260. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_runtime.py +0 -0
  261. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_runtime_color.py +0 -0
  262. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_skill_commands.py +0 -0
  263. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_stdin_sniffer.py +0 -0
  264. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_writes_respx.py +0 -0
  265. {netbox_super_cli-1.7.0/tests/config → netbox_super_cli-1.8.1/tests/cli/writes}/__init__.py +0 -0
  266. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/writes/test_apply.py +0 -0
  267. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/writes/test_bulk.py +0 -0
  268. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/writes/test_confirmation.py +0 -0
  269. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/writes/test_handler_helpers.py +0 -0
  270. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/writes/test_handlers_audit.py +0 -0
  271. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/writes/test_input.py +0 -0
  272. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/writes/test_preflight.py +0 -0
  273. {netbox_super_cli-1.7.0/tests/http → netbox_super_cli-1.8.1/tests/config}/__init__.py +0 -0
  274. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/config/test_loader.py +0 -0
  275. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/config/test_saved_search_fallback.py +0 -0
  276. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/config/test_saved_searches.py +0 -0
  277. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/config/test_settings_private_dir.py +0 -0
  278. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/config/test_writer_atomicity.py +0 -0
  279. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/config/test_writer_dotted_paths.py +0 -0
  280. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/config/test_writer_roundtrip.py +0 -0
  281. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/__init__.py +0 -0
  282. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/docker-compose.yml +0 -0
  283. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/test_audit_redaction.py +0 -0
  284. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/test_auth_error_envelope.py +0 -0
  285. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/test_bulk_create_with_loop_fallback.py +0 -0
  286. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/test_full_cycle.py +0 -0
  287. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/test_ndjson.py +0 -0
  288. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/test_preflight_blocks_apply.py +0 -0
  289. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/test_validation_error_envelope_from_netbox.py +0 -0
  290. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/wait_for_netbox.sh +0 -0
  291. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/fixtures/profiles/single_profile.yaml +0 -0
  292. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/fixtures/responses/auth_401.json +0 -0
  293. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/fixtures/responses/circuits_providers_list.json +0 -0
  294. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/fixtures/responses/dcim_devices_get.json +0 -0
  295. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/fixtures/responses/dcim_devices_list_p1.json +0 -0
  296. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/fixtures/responses/dcim_devices_list_p2.json +0 -0
  297. {netbox_super_cli-1.7.0/tests/model → netbox_super_cli-1.8.1/tests/http}/__init__.py +0 -0
  298. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/http/test_audit.py +0 -0
  299. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/http/test_audit_permissions.py +0 -0
  300. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/http/test_audit_redaction.py +0 -0
  301. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/http/test_client_redaction_threading.py +0 -0
  302. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/http/test_errors.py +0 -0
  303. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/http/test_retry.py +0 -0
  304. {netbox_super_cli-1.7.0/tests/output → netbox_super_cli-1.8.1/tests/model}/__init__.py +0 -0
  305. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/model/test_command_model.py +0 -0
  306. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/model/test_request_body_shape.py +0 -0
  307. {netbox_super_cli-1.7.0/tests/savedfilters → netbox_super_cli-1.8.1/tests/output}/__init__.py +0 -0
  308. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_colors.py +0 -0
  309. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_console.py +0 -0
  310. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_csv.py +0 -0
  311. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_errors.py +0 -0
  312. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_errors_aliases.py +0 -0
  313. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_errors_color.py +0 -0
  314. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_explain.py +0 -0
  315. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_explain_color.py +0 -0
  316. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_flatten.py +0 -0
  317. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_input_error_envelope.py +0 -0
  318. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_json.py +0 -0
  319. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_jsonl.py +0 -0
  320. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_render_dispatch.py +0 -0
  321. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_table.py +0 -0
  322. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_table_color.py +0 -0
  323. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_yaml.py +0 -0
  324. {netbox_super_cli-1.7.0/tests/schema → netbox_super_cli-1.8.1/tests/savedfilters}/__init__.py +0 -0
  325. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/savedfilters/test_custom_fields.py +0 -0
  326. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/savedfilters/test_objecttypes.py +0 -0
  327. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/savedfilters/test_params.py +0 -0
  328. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/savedfilters/test_store.py +0 -0
  329. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/savedfilters/test_tags.py +0 -0
  330. {netbox_super_cli-1.7.0/tests/scripts → netbox_super_cli-1.8.1/tests/schema}/__init__.py +0 -0
  331. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/schema/test_hashing.py +0 -0
  332. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/schema/test_loader.py +0 -0
  333. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/schema/test_models.py +0 -0
  334. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/schema/test_source.py +0 -0
  335. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/schema/test_source_ttl.py +0 -0
  336. {netbox_super_cli-1.7.0/tests/skill → netbox_super_cli-1.8.1/tests/scripts}/__init__.py +0 -0
  337. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/scripts/test_gen_docs.py +0 -0
  338. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/scripts/test_sync_agents_md.py +0 -0
  339. {netbox_super_cli-1.7.0/tests/tui → netbox_super_cli-1.8.1/tests/skill}/__init__.py +0 -0
  340. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/skill/test_bundle.py +0 -0
  341. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/test_packaging.py +0 -0
  342. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_app.py +0 -0
  343. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_bindings.py +0 -0
  344. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_bulk_apply.py +0 -0
  345. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_bulk_diff.py +0 -0
  346. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_bulk_diff_modal.py +0 -0
  347. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_bulk_edit_form.py +0 -0
  348. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_bulk_import_isolation.py +0 -0
  349. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_bulk_summary.py +0 -0
  350. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_catalog.py +0 -0
  351. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_column_chooser.py +0 -0
  352. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_columns.py +0 -0
  353. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_detail_screen.py +0 -0
  354. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_diff.py +0 -0
  355. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_diff_modal.py +0 -0
  356. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_edit_form.py +0 -0
  357. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_errors.py +0 -0
  358. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_filter_screen.py +0 -0
  359. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_filters.py +0 -0
  360. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_fk_resolve.py +0 -0
  361. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_forms.py +0 -0
  362. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_global_search.py +0 -0
  363. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_help_overlay.py +0 -0
  364. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_keymap.py +0 -0
  365. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_picker.py +0 -0
  366. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_record_picker.py +0 -0
  367. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_relations.py +0 -0
  368. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_saved_filter_integration.py +0 -0
  369. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_search.py +0 -0
  370. {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_selection.py +0 -0
@@ -13,8 +13,8 @@ jobs:
13
13
  startup-time:
14
14
  runs-on: ubuntu-latest
15
15
  steps:
16
- - uses: actions/checkout@v7
17
- - uses: astral-sh/setup-uv@v7
16
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
17
+ - uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
18
18
  - name: Install
19
19
  run: uv sync --all-extras --dev
20
20
  - name: Benchmark
@@ -41,13 +41,13 @@ jobs:
41
41
  actions: read # Required for Claude to read CI results on PRs
42
42
  steps:
43
43
  - name: Checkout repository
44
- uses: actions/checkout@v7
44
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
45
45
  with:
46
46
  fetch-depth: 1
47
47
 
48
48
  - name: Run Claude Code
49
49
  id: claude
50
- uses: anthropics/claude-code-action@v1
50
+ uses: anthropics/claude-code-action@db77d4d3c98f3f6380e7cd45ffba2342a3dbde3c # v1
51
51
  with:
52
52
  claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
53
53
 
@@ -26,9 +26,9 @@ jobs:
26
26
  build:
27
27
  runs-on: ubuntu-latest
28
28
  steps:
29
- - uses: actions/checkout@v7
29
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
30
30
  - name: Install uv
31
- uses: astral-sh/setup-uv@v7
31
+ uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
32
32
  with:
33
33
  enable-cache: true
34
34
  - name: Install Python
@@ -39,7 +39,7 @@ jobs:
39
39
  run: uv run zensical build --strict
40
40
  - name: Upload Pages artifact
41
41
  if: github.ref_type == 'tag'
42
- uses: actions/upload-pages-artifact@v5
42
+ uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5
43
43
  with:
44
44
  path: site
45
45
 
@@ -52,4 +52,4 @@ jobs:
52
52
  url: ${{ steps.deployment.outputs.page_url }}
53
53
  steps:
54
54
  - id: deployment
55
- uses: actions/deploy-pages@v5
55
+ uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5
@@ -6,6 +6,11 @@ on:
6
6
  pull_request:
7
7
  paths:
8
8
  - 'nsc/http/**'
9
+ - 'nsc/branching/**'
10
+ - 'nsc/cli/branch_commands.py'
11
+ - 'nsc/auth/**'
12
+ - 'nsc/cli/login_commands.py'
13
+ - 'nsc/cli/profiles_commands.py'
9
14
  - 'nsc/cli/handlers.py'
10
15
  - 'nsc/cli/registration.py'
11
16
  - 'nsc/cli/writes/**'
@@ -34,8 +39,8 @@ jobs:
34
39
  env:
35
40
  NETBOX_IMAGE: netboxcommunity/netbox:${{ matrix.netbox-version }}
36
41
  steps:
37
- - uses: actions/checkout@v7
38
- - uses: astral-sh/setup-uv@v7
42
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
43
+ - uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
39
44
  - name: Sync deps
40
45
  run: uv sync --frozen
41
46
  - name: Start NetBox
@@ -54,3 +59,33 @@ jobs:
54
59
  - name: Stop NetBox
55
60
  if: always()
56
61
  run: docker compose -f tests/e2e/docker-compose.yml down -v
62
+
63
+ e2e-branching:
64
+ name: e2e-branching (v4.7.3 + branching 1.2.2)
65
+ runs-on: ubuntu-latest
66
+ timeout-minutes: 20
67
+ env:
68
+ NETBOX_IMAGE: netboxcommunity/netbox:v4.7.3
69
+ COMPOSE: -f tests/e2e/docker-compose.yml -f tests/e2e/docker-compose.branching.yml
70
+ steps:
71
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
72
+ - uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
73
+ - name: Sync deps
74
+ run: uv sync --frozen
75
+ - name: Build and start NetBox with Branching
76
+ run: docker compose $COMPOSE up -d --build
77
+ - name: Wait for NetBox
78
+ run: tests/e2e/wait_for_netbox.sh
79
+ - name: Run branching e2e tests
80
+ env:
81
+ NSC_E2E: '1'
82
+ NSC_E2E_BRANCHING: '1'
83
+ NSC_URL: http://127.0.0.1:8080
84
+ NSC_TOKEN: '0123456789abcdef0123456789abcdef01234567'
85
+ run: uv run pytest tests/e2e/test_branching.py -v
86
+ - name: Dump container logs on failure
87
+ if: failure()
88
+ run: docker compose $COMPOSE logs
89
+ - name: Stop NetBox
90
+ if: always()
91
+ run: docker compose $COMPOSE down -v
@@ -12,9 +12,9 @@ jobs:
12
12
  lint:
13
13
  runs-on: ubuntu-latest
14
14
  steps:
15
- - uses: actions/checkout@v7
15
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
16
16
  - name: Install uv
17
- uses: astral-sh/setup-uv@v7
17
+ uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
18
18
  with:
19
19
  enable-cache: true
20
20
  - name: Install Python
@@ -31,9 +31,9 @@ jobs:
31
31
  docs-reference-fresh:
32
32
  runs-on: ubuntu-latest
33
33
  steps:
34
- - uses: actions/checkout@v7
34
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
35
35
  - name: Install uv
36
- uses: astral-sh/setup-uv@v7
36
+ uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
37
37
  with:
38
38
  enable-cache: true
39
39
  - name: Install Python
@@ -46,9 +46,9 @@ jobs:
46
46
  agents-md-fresh:
47
47
  runs-on: ubuntu-latest
48
48
  steps:
49
- - uses: actions/checkout@v7
49
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
50
50
  - name: Install uv
51
- uses: astral-sh/setup-uv@v7
51
+ uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
52
52
  with:
53
53
  enable-cache: true
54
54
  - name: Install Python
@@ -39,7 +39,7 @@ jobs:
39
39
  # prerequisites).
40
40
  steps:
41
41
  - name: Checkout (full history for changelog notes)
42
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
42
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
43
43
  with:
44
44
  fetch-depth: 0
45
45
 
@@ -62,7 +62,7 @@ jobs:
62
62
  echo "Tag $GITHUB_REF_NAME ($GITHUB_SHA) is on main."
63
63
 
64
64
  - name: Install uv
65
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
65
+ uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
66
66
  with:
67
67
  enable-cache: true
68
68
 
@@ -110,7 +110,7 @@ jobs:
110
110
  fi
111
111
 
112
112
  - name: Publish to PyPI (trusted publishing)
113
- uses: pypa/gh-action-pypi-publish@release/v1
113
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
114
114
  with:
115
115
  # No `password:` — trusted publishing uses the OIDC token bound
116
116
  # to id-token: write above. PyPI must have a Trusted Publisher
@@ -16,9 +16,9 @@ jobs:
16
16
  matrix:
17
17
  python: ["3.12", "3.13", "3.14"]
18
18
  steps:
19
- - uses: actions/checkout@v7
19
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
20
20
  - name: Install uv
21
- uses: astral-sh/setup-uv@v7
21
+ uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
22
22
  with:
23
23
  enable-cache: true
24
24
  - name: Install Python
@@ -32,6 +32,7 @@ repos:
32
32
  - structlog>=24.1
33
33
  - platformdirs>=4.2
34
34
  - textual>=0.50
35
+ - keyring>=25.0
35
36
  - types-PyYAML>=6.0
36
37
  args: [--strict]
37
38
  files: ^(nsc|scripts)/
@@ -20,6 +20,7 @@ This is the contributor guide for AI agents (and humans!) modifying this repo. T
20
20
  - `nsc/config/` — config loader + Pydantic models + ruamel.yaml round-trip writer.
21
21
  - `nsc/cache/` — disk cache for generated command-models.
22
22
  - `nsc/auth/` — login verification helpers (pre-flight probes, token rotate).
23
+ - `nsc/branching/` — NetBox Branching: branch name→schema_id resolution, lifecycle API calls, job polling. Framework-free; `nsc/http` must not import it (the client takes a resolver callable).
23
24
  - `nsc/aliases/` — curated alias resolver (`ls`, `get`, `rm`, `search`). Framework-free.
24
25
  - `nsc/completion/` — dynamic shell-completion: framework-free providers + cheap on-disk cache probe + Typer `shell_complete` callbacks.
25
26
  - `nsc/skill/` — bundle-path helper for the portable `SKILL.md` shipped in the wheel.
@@ -2,6 +2,115 @@
2
2
 
3
3
  All notable changes to netbox-super-cli are tracked here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loosely. From v1.0.0 onward, releases follow [Semantic Versioning](https://semver.org/) and the version in `pyproject.toml` matches the git tag. Pre-1.0 milestones (Phase 1-5) were pinned by tag while `pyproject.toml` stayed at `0.0.1`.
4
4
 
5
+ ## Unreleased
6
+
7
+ ## v1.8.1 — 2026-10-22
8
+
9
+ Patch release. Fixes two NetBox Branching issues found after v1.8.0.
10
+
11
+ ### Fixed
12
+
13
+ - **`--branch` after a subcommand no longer switches branches** ([#170]). It is
14
+ a global option only before the subcommand. After it, `--branch` belongs to
15
+ that command (for example a plugin's `branch` filter) and is left alone.
16
+ - **Branch failures while loading `--saved` filters honour `-o json`** ([#173]).
17
+ They now emit the branch error's structured envelope (with its usual exit
18
+ code) in the requested format instead of falling through to the catch-all
19
+ table renderer. `nsc --branch X <meta command>` (e.g. `profiles list`) is
20
+ also recognised as a meta command again instead of bootstrapping the schema.
21
+
22
+ ## v1.8.0 — 2026-10-22
23
+
24
+ Minor release. Adds NetBox Branching support (`--branch`, `NSC_BRANCH`,
25
+ `nsc branch …`), so changes can be staged in a branch, reviewed and merged.
26
+ Also adds OS keyring token storage, lazy TUI pagination with CLI truncation
27
+ notices, and a fix for `nsc login` reporting the wrong user.
28
+
29
+ ### Added
30
+
31
+ - **NetBox Branching support** ([#166]). Run any command inside a
32
+ [NetBox Branching](https://netboxlabs.com/docs/extensions/branching/) branch
33
+ with `--branch NAME`, `NSC_BRANCH`, or a sticky per-profile branch set by
34
+ `nsc branch use NAME` (`--branch main` forces main). nsc resolves the name
35
+ to the plugin's `schema_id` and sends `X-NetBox-Branch` on every request.
36
+ Each command run in a branch prints `⎇ branch: <name>` on stderr, and the
37
+ TUI header shows it. A missing or non-`ready` branch fails loudly (exit
38
+ 9/12) and never falls back to main. New `nsc branch` group: `list`, `show`,
39
+ `current`, `create` (waits until ready, `--use`), `use` / `use --main`,
40
+ `diff`, and `sync` / `merge` / `revert` / `archive` / `delete`. Like every
41
+ nsc write, these are dry-run unless you pass `--apply`. Conflicts exit 10
42
+ with `details.conflicts`, and `--acknowledge-conflicts` proceeds anyway.
43
+ Targets NetBox 4.7 with `netboxlabs-netbox-branching` 1.2.x; a new
44
+ `e2e-branching` CI job runs it live. See the
45
+ [branching guide](docs/guides/branching.md).
46
+ - **OS keyring token storage** ([#1]). A new `token: !keyring NAME` config tag
47
+ resolves the token from the OS keyring (macOS Keychain, Secret Service,
48
+ Windows Credential Manager) under service `nsc`, username `NAME`.
49
+ `nsc login --new|--rotate --store keyring [--keyring-name NAME]` verifies the
50
+ token, writes it to the keyring, and stores only the `!keyring` reference in
51
+ `~/.nsc/config.yaml`, so the plaintext token never touches disk. Any
52
+ invocation that builds the dynamic command tree reads the keyring, including
53
+ bare `nsc` and `nsc --help`; shell completion and the meta commands
54
+ (`config`, `profiles`, `cache`, `init`, `commands`, `skill`) do not. A missing
55
+ entry or an unavailable backend yields a `config` error envelope (exit 12),
56
+ except that `--help` on a static command still prints usage. `nsc login`
57
+ refuses to overwrite a keyring entry that another profile still references
58
+ (for example after `nsc profiles rename`) and asks for a distinct
59
+ `--keyring-name`. `keyring`
60
+ is a new core dependency, imported lazily so it adds no startup cost. See
61
+ the new [OS keyring storage guide](docs/guides/keyring.md).
62
+ `--keyring-name` is stripped of surrounding whitespace, and a blank name is
63
+ rejected as a usage error before the token prompt.
64
+
65
+ ### Fixed
66
+
67
+ - **`nsc login` / `nsc profiles add` no longer report a random user** ([#150]).
68
+ The identity probe used to take the owner of the first row of
69
+ `/api/users/tokens/`, which for admins is often another user's token. The
70
+ caller is now identified from the token they presented: v2 (`nbt_…`) tokens
71
+ are looked up by their non-secret key id; v1 tokens are matched client-side
72
+ against the retrievable plaintext when NetBox exposes it
73
+ (`ALLOW_TOKEN_RETRIEVAL`; the plaintext is never sent in a query string), or
74
+ by every visible token sharing one owner. When the user cannot be determined reliably, nsc prints
75
+ `authenticated (user unknown)` instead of guessing.
76
+ - **`nsc tui` lists are no longer capped at the first page** ([#151]). The list
77
+ screen loads 100 rows at a time and fetches the next chunk (following NetBox
78
+ `next` links) when the cursor reaches the last row or you press <kbd>m</kbd>.
79
+ The header shows `N of M` (rows loaded vs. the server's `count`). Loading stops
80
+ at 10,000 rows with a hint to filter instead. A page that fails mid-chunk
81
+ keeps the rows already received (retry with <kbd>m</kbd>), and a refresh no
82
+ longer drops selections made beyond the first chunk.
83
+ - **A negative `--limit` is now a usage error** instead of a Python traceback,
84
+ and `defaults.page_size` must be at least 1.
85
+ - **CLI `list` / `ls` / `search` now report truncation** ([#151]). When the
86
+ default page size hides records the server still has, a one-line
87
+ `nsc: showing 50 of 1234 results; pass --all ...` notice is printed on stderr
88
+ (stdout is unchanged). The default page also no longer fetches one extra page
89
+ from the server just to discard it.
90
+ - **Pages after the first keep multi-value filters** ([#151]). Following a
91
+ NetBox `next` link no longer drops repeated query keys, so
92
+ `--site a --site b --all` returns both sites on every page.
93
+ - **Pagination works when NetBox is served under a sub-path** (`BASE_PATH`,
94
+ e.g. `https://host/netbox`). The second and later pages no longer 404 from a
95
+ doubled path prefix.
96
+
97
+ ### Changed
98
+
99
+ - `NetBoxClient.paginate` now returns a lazy, resumable `Pager`
100
+ (`nsc/http/pagination.py`) exposing the server `total` and `has_more`, shared
101
+ by the CLI and the TUI.
102
+ - `nsc login --store` now rejects unknown values. Previously any value other
103
+ than `env` silently fell back to plaintext, so a typo could write the token
104
+ to disk. `nsc login --rotate` with no `--store` keeps an existing
105
+ `!keyring` reference instead of replacing it with plaintext.
106
+
107
+ [#1]: https://github.com/thomaschristory/netbox-super-cli/issues/1
108
+ [#166]: https://github.com/thomaschristory/netbox-super-cli/issues/166
109
+ [#170]: https://github.com/thomaschristory/netbox-super-cli/issues/170
110
+ [#173]: https://github.com/thomaschristory/netbox-super-cli/issues/173
111
+ [#150]: https://github.com/thomaschristory/netbox-super-cli/issues/150
112
+ [#151]: https://github.com/thomaschristory/netbox-super-cli/issues/151
113
+
5
114
  ## v1.7.0 — 2026-09-10
6
115
 
7
116
  Minor release. Migrates the HTTP stack from `httpx` to Pydantic's maintained
@@ -13,6 +13,7 @@ This is the contributor guide for AI agents (and humans!) modifying this repo. T
13
13
  - `nsc/config/` — config loader + Pydantic models + ruamel.yaml round-trip writer.
14
14
  - `nsc/cache/` — disk cache for generated command-models.
15
15
  - `nsc/auth/` — login verification helpers (pre-flight probes, token rotate).
16
+ - `nsc/branching/` — NetBox Branching: branch name→schema_id resolution, lifecycle API calls, job polling. Framework-free; `nsc/http` must not import it (the client takes a resolver callable).
16
17
  - `nsc/aliases/` — curated alias resolver (`ls`, `get`, `rm`, `search`). Framework-free.
17
18
  - `nsc/completion/` — dynamic shell-completion: framework-free providers + cheap on-disk cache probe + Typer `shell_complete` callbacks.
18
19
  - `nsc/skill/` — bundle-path helper for the portable `SKILL.md` shipped in the wheel.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: netbox-super-cli
3
- Version: 1.7.0
3
+ Version: 1.8.1
4
4
  Summary: Dynamic NetBox CLI generated from the live OpenAPI schema.
5
5
  Project-URL: Homepage, https://github.com/thomaschristory/netbox-super-cli
6
6
  Project-URL: Documentation, https://thomaschristory.github.io/netbox-super-cli/
@@ -24,6 +24,7 @@ Classifier: Topic :: System :: Networking
24
24
  Requires-Python: >=3.12
25
25
  Requires-Dist: click>=8.1
26
26
  Requires-Dist: httpx2>=2.5
27
+ Requires-Dist: keyring>=25.0
27
28
  Requires-Dist: platformdirs>=4.2
28
29
  Requires-Dist: pydantic>=2.7
29
30
  Requires-Dist: rich>=13.7
@@ -64,6 +65,7 @@ One binary, any NetBox version, every plugin endpoint — the schema, not hand-w
64
65
  - **Plugins just work.** If your install has plugins, their endpoints appear as commands automatically.
65
66
  - **Multi-instance.** Named profiles per NetBox instance, plus env-var overrides.
66
67
  - **Safe by default.** POST/PATCH/PUT/DELETE preview as dry-runs unless you pass `--apply`.
68
+ - **NetBox Branching.** Stage changes in a branch (`--branch`, `NSC_BRANCH`, `nsc branch use`), review with `nsc branch diff`, merge with `nsc branch merge --apply`. See [the guide](docs/guides/branching.md).
67
69
  - **Agent-friendly.** Deterministic command shape, machine-readable JSON output, stable error envelope with documented exit codes.
68
70
  - **Interactive TUI.** `nsc tui` opens a keyboard-driven terminal UI — see below.
69
71
 
@@ -208,6 +210,25 @@ The wire body sent to NetBox is **not** redacted — only the audit log. A faile
208
210
 
209
211
  For a stricter posture, set `audit_redaction: full` in `~/.nsc/config.yaml` (the default is `safe`, the field-level redaction described above). In `full` mode every audit line keeps only `{method, url, status_code, timestamp, profile}` — all request and response bodies are dropped, and the `url` is sanitized (query string and any `user:pass@` credentials stripped).
210
212
 
213
+ ## NetBox Branching
214
+
215
+ If your NetBox runs the [Branching plugin](https://netboxlabs.com/docs/extensions/branching/),
216
+ any command can stage its changes in a branch for review:
217
+
218
+ ```sh
219
+ nsc branch create add-london --use # create, wait until ready, make it sticky
220
+ nsc dcim sites create -f london.yaml --apply # lands in the branch; stderr shows "⎇ branch: add-london"
221
+ nsc branch diff # review the staged changes
222
+ nsc branch merge # dry-run, validated server-side
223
+ nsc branch merge --apply # merge into main
224
+ nsc branch use --main # back to main
225
+ ```
226
+
227
+ `--branch NAME` and `NSC_BRANCH` select a branch for a single command or a
228
+ whole shell, and agents should use these. A merged, missing or not-ready branch
229
+ fails loudly and never falls back to main. See the
230
+ [branching guide](docs/guides/branching.md).
231
+
211
232
  ## Curated aliases
212
233
 
213
234
  `nsc ls`, `nsc get`, `nsc rm`, and `nsc search` are short verbs over the dynamic
@@ -29,6 +29,7 @@ One binary, any NetBox version, every plugin endpoint — the schema, not hand-w
29
29
  - **Plugins just work.** If your install has plugins, their endpoints appear as commands automatically.
30
30
  - **Multi-instance.** Named profiles per NetBox instance, plus env-var overrides.
31
31
  - **Safe by default.** POST/PATCH/PUT/DELETE preview as dry-runs unless you pass `--apply`.
32
+ - **NetBox Branching.** Stage changes in a branch (`--branch`, `NSC_BRANCH`, `nsc branch use`), review with `nsc branch diff`, merge with `nsc branch merge --apply`. See [the guide](docs/guides/branching.md).
32
33
  - **Agent-friendly.** Deterministic command shape, machine-readable JSON output, stable error envelope with documented exit codes.
33
34
  - **Interactive TUI.** `nsc tui` opens a keyboard-driven terminal UI — see below.
34
35
 
@@ -173,6 +174,25 @@ The wire body sent to NetBox is **not** redacted — only the audit log. A faile
173
174
 
174
175
  For a stricter posture, set `audit_redaction: full` in `~/.nsc/config.yaml` (the default is `safe`, the field-level redaction described above). In `full` mode every audit line keeps only `{method, url, status_code, timestamp, profile}` — all request and response bodies are dropped, and the `url` is sanitized (query string and any `user:pass@` credentials stripped).
175
176
 
177
+ ## NetBox Branching
178
+
179
+ If your NetBox runs the [Branching plugin](https://netboxlabs.com/docs/extensions/branching/),
180
+ any command can stage its changes in a branch for review:
181
+
182
+ ```sh
183
+ nsc branch create add-london --use # create, wait until ready, make it sticky
184
+ nsc dcim sites create -f london.yaml --apply # lands in the branch; stderr shows "⎇ branch: add-london"
185
+ nsc branch diff # review the staged changes
186
+ nsc branch merge # dry-run, validated server-side
187
+ nsc branch merge --apply # merge into main
188
+ nsc branch use --main # back to main
189
+ ```
190
+
191
+ `--branch NAME` and `NSC_BRANCH` select a branch for a single command or a
192
+ whole shell, and agents should use these. A merged, missing or not-ready branch
193
+ fails loudly and never falls back to main. See the
194
+ [branching guide](docs/guides/branching.md).
195
+
176
196
  ## Curated aliases
177
197
 
178
198
  `nsc ls`, `nsc get`, `nsc rm`, and `nsc search` are short verbs over the dynamic
@@ -0,0 +1,12 @@
1
+ # Security policy
2
+
3
+ ## Supported versions
4
+
5
+ Only the latest release gets security fixes.
6
+
7
+ ## Reporting a vulnerability
8
+
9
+ Do not open a public issue. Use the private vulnerability reporting of GitHub:
10
+ [Report a vulnerability](https://github.com/thomaschristory/netbox-super-cli/security/advisories/new)
11
+ (**Security > Report a vulnerability** on the repository). Only the maintainer sees the report.
12
+ The maintainer replies, fixes the problem, and publishes an advisory with the fix.
@@ -20,6 +20,15 @@
20
20
  `final_attempt`; redaction is applied on every write, so a failed
21
21
  retry never unredacts.
22
22
  - Pagination helper that follows `next` URLs (used by `--all`).
23
+ - Optional NetBox Branching context. Given a `branch_resolver`, the client
24
+ resolves the branch lazily on its first request: the resolver's own lookups
25
+ go out unbranched, and every later request carries
26
+ `X-NetBox-Branch: <schema_id>`. Resolution is serialized under a lock, so
27
+ concurrent `--workers` threads wait instead of racing ahead without the
28
+ header. A failed resolution is stored and raised again on every later call,
29
+ so once a branch is selected no request can reach main. The resolver
30
+ itself lives in `nsc/branching/` (`nsc/http` does not import it), and
31
+ `nsc branch …` commands build a client without one.
23
32
  - Audit log appender at `~/.nsc/logs/audit.jsonl` — written for writes
24
33
  always, and for any request when `--debug` is set.
25
34
 
@@ -16,6 +16,7 @@ nsc/
16
16
  ├── config/ # Pydantic config models + ruamel.yaml writer
17
17
  ├── cache/ # On-disk cache for generated CommandModels
18
18
  ├── auth/ # Login verification helpers (verify probe, token rotate)
19
+ ├── branching/ # NetBox Branching: branch lookup, lifecycle calls, job polling
19
20
  ├── aliases/ # Curated alias resolver (ls/get/rm/search)
20
21
  ├── completion/ # Dynamic shell-completion: providers + cache probe + Typer callbacks
21
22
  ├── skill/ # Bundle-path helper for the portable SKILL.md
@@ -70,6 +70,22 @@ nsc dcim devices create --field name=foo --field site=1 --apply
70
70
  Add `--explain` to a dry-run to see the schema reasoning ("PATCH because of
71
71
  operationId `dcim_devices_partial_update`").
72
72
 
73
+ ## Branches (NetBox Branching)
74
+
75
+ If your server runs the NetBox Branching plugin, any command can run inside a
76
+ branch instead of main. Pick one with `--branch NAME`, `NSC_BRANCH=NAME`, or
77
+ make it sticky on the profile with `nsc branch use NAME`. While a branch is
78
+ active, every command prints `⎇ branch: NAME` on stderr. If the branch can't be
79
+ used (merged, missing, not ready), the command fails without sending anything.
80
+ It never quietly falls back to main. See [NetBox Branching](../guides/branching.md).
81
+
82
+ ```sh
83
+ nsc branch create add-london --use
84
+ nsc dcim sites create --field name=London --field slug=london --apply # staged in the branch
85
+ nsc branch diff
86
+ nsc branch merge --apply
87
+ ```
88
+
73
89
  ## Audit log
74
90
 
75
91
  Every wire request and its response are appended to
@@ -54,9 +54,13 @@ nsc login --rotate --profile prod # rotate the token
54
54
  nsc login --fetch-schema # verify, then fetch & cache the live schema
55
55
  ```
56
56
 
57
- `nsc login` probes `GET /api/status/` and `GET /api/users/tokens/?limit=1`
57
+ `nsc login` probes `GET /api/status/` and `GET /api/users/tokens/`
58
58
  (both must succeed) and prints `✓ authenticated as <user>, NetBox <version>`
59
- on success. On failure it emits the standard auth error envelope
59
+ on success. NetBox has no "current user" endpoint, so the user is derived from
60
+ the token you presented; when that can't be done reliably (e.g. a v1 token
61
+ held by an admin who can see other users' tokens) it prints
62
+ `✓ authenticated (user unknown), NetBox <version>` rather than guessing.
63
+ On failure it emits the standard auth error envelope
60
64
  (`type: auth`, exit 8).
61
65
 
62
66
  `--new` requires both `--profile` and `--url`, prompts for the token
@@ -0,0 +1,140 @@
1
+ # NetBox Branching
2
+
3
+ If your NetBox runs the [NetBox Branching plugin](https://netboxlabs.com/docs/extensions/branching/)
4
+ (`netboxlabs-netbox-branching`), `nsc` can make your changes in a **branch**
5
+ instead of on main. You stage writes in the branch, review the diff, and then
6
+ merge them into main. This works the same way for people and for AI agents.
7
+
8
+ Requires NetBox 4.7 and plugin 1.2.x (tested against NetBox 4.7.3 and plugin 1.2.2).
9
+
10
+ ```sh
11
+ nsc branch create add-london --use # create, wait until ready, make it sticky
12
+ nsc dcim sites create -f london.yaml --apply # lands in the branch, not main
13
+ nsc branch diff # review what the branch changes
14
+ nsc branch merge # dry-run: validates the merge server-side
15
+ nsc branch merge --apply # merge into main
16
+ nsc branch use --main # back to main
17
+ ```
18
+
19
+ ## Choosing the branch
20
+
21
+ Every command, including dynamic resource commands, aliases and the TUI, runs
22
+ in the active branch. `nsc` sends the plugin's `X-NetBox-Branch` header with
23
+ the branch's `schema_id`. You refer to a branch by name, or by schema_id if
24
+ you prefer.
25
+
26
+ The active branch comes from the first of these that is set:
27
+
28
+ | Source | Example | Lifetime |
29
+ |---|---|---|
30
+ | `--branch NAME` | `nsc --branch add-london ls sites` | one command |
31
+ | `NSC_BRANCH` | `export NSC_BRANCH=add-london` | the shell / CI job |
32
+ | profile `branch:` | written by `nsc branch use NAME` | sticky, until `nsc branch use --main` |
33
+
34
+ `--branch main` or `NSC_BRANCH=main` forces main for that invocation even when
35
+ the profile has a sticky branch.
36
+
37
+ `--branch` is a global option and must come **before** the subcommand
38
+ (`nsc --branch X dcim sites list`). After the subcommand, `--branch` belongs to
39
+ that command, for example the Branching plugin's own `changes list` filter, and
40
+ doesn't switch branches.
41
+
42
+ `nsc branch use` needs a saved profile to store the branch on. With only
43
+ `NSC_URL`/`NSC_TOKEN` set (no profile), use `NSC_BRANCH` or `--branch`.
44
+
45
+ ## Knowing where you are
46
+
47
+ When a branch is active, every command prints one line to **stderr**:
48
+
49
+ ```
50
+ ⎇ branch: add-london
51
+ ```
52
+
53
+ stdout is untouched, so `-o json` output piped elsewhere stays clean. The TUI
54
+ shows the branch in its header in the warning colour. `nsc branch current`
55
+ prints the active branch and where it came from (`flag`, `env` or `profile`),
56
+ or `main`.
57
+
58
+ Every request made in a branch is recorded in the [audit log](audit-log.md)
59
+ with its `X-Netbox-Branch` header (the branch's schema_id). When a command
60
+ fails while a branch is active, its error envelope names the branch in
61
+ `details.branch`, whatever the failure is.
62
+
63
+ A branch that is literally named `main` can still be selected by its
64
+ schema_id. `nsc branch use` stores the schema_id for such a branch, because the
65
+ name would read back as "force main".
66
+
67
+ ## When the branch can't be used
68
+
69
+ If the active branch doesn't exist, or exists but isn't `ready` (it's
70
+ merged, archived, still provisioning, or failed), the command **fails without
71
+ sending anything** and never falls back to main:
72
+
73
+ | Situation | Error type | Exit |
74
+ |---|---|---|
75
+ | Branching plugin not installed | `config` | 12 |
76
+ | Branch not found | `not_found` | 9 |
77
+ | Branch not `ready` (e.g. merged) | `config` | 12 |
78
+ | Name matches one branch and schema_id of another | `input_error` | 4 |
79
+
80
+ The message says how to get back to main: `nsc branch use --main`, or
81
+ `--branch main` for a single command. `nsc branch …` commands never run inside
82
+ a branch, so `nsc branch use --main` always works.
83
+
84
+ ## Commands
85
+
86
+ | Command | What it does |
87
+ |---|---|
88
+ | `nsc branch list` | All branches; the active one has `active: true`. |
89
+ | `nsc branch show [NAME]` | One branch (default: the active one). |
90
+ | `nsc branch current` | Active branch and its source, or `main`. No network call. |
91
+ | `nsc branch create NAME [--description] [--use] [--no-wait]` | Create the branch and wait until it's `ready`. `--use` then makes it sticky. |
92
+ | `nsc branch use NAME` / `--main` | Set / clear the profile's sticky branch. Checks that the branch is `ready` first. |
93
+ | `nsc branch diff [NAME]` | Staged changes: action, object type, object, changed fields. `-o json` gives the full plugin records. |
94
+ | `nsc branch sync [NAME]` | Pull main's changes into the branch. |
95
+ | `nsc branch merge [NAME]` | Merge the branch into main. |
96
+ | `nsc branch revert [NAME]` | Undo a merged branch on main. |
97
+ | `nsc branch archive [NAME]` | Archive a merged branch (drops its schema). |
98
+ | `nsc branch delete NAME` | Delete a branch. |
99
+
100
+ ### Dry-run by default
101
+
102
+ Like every other `nsc` write, `sync`, `merge`, `revert`, `archive` and
103
+ `delete` change nothing unless you pass `--apply`:
104
+
105
+ - `sync`, `merge` and `revert` without `--apply` still run the plugin's job
106
+ with `commit: false`, so the server checks that the operation would succeed
107
+ and then rolls it back.
108
+ - `archive` and `delete` without `--apply` only print what they would do.
109
+
110
+ `sync`, `merge` and `revert` wait for the background job to finish (up to
111
+ `--timeout`, 600 s by default) and print the job's log lines on stderr. Pass
112
+ `--no-wait` to return as soon as the job is queued.
113
+
114
+ A job that ends in `errored` exits **4** (`validation`), with the job's error
115
+ in `details.job_error`. This happens, for example, when a Change Request
116
+ policy blocks the merge.
117
+
118
+ ### Conflicts
119
+
120
+ If main and the branch changed the same fields of an object, `sync` and
121
+ `merge` fail with exit **10** (`conflict`), and `details.conflicts` lists each
122
+ object together with its original, branch and main values. After reviewing
123
+ them, re-run with `--acknowledge-conflicts` to proceed; the branch's values
124
+ win.
125
+
126
+ ## For agents
127
+
128
+ Agents should set `NSC_BRANCH` rather than `nsc branch use`. It works without
129
+ a saved profile, and it doesn't change the user's config:
130
+
131
+ ```sh
132
+ nsc branch create agent-change-123 -o json
133
+ export NSC_BRANCH=agent-change-123
134
+ nsc dcim devices create -f devices.ndjson --apply -o json
135
+ nsc branch diff agent-change-123 -o json # hand this to a human for review
136
+ ```
137
+
138
+ The commands are the same for people and agents. Whether an agent may run
139
+ `nsc branch merge --apply` is up to the session's own rules; `nsc` doesn't
140
+ enforce it.