netbox-super-cli 1.0.1__tar.gz → 1.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/.gitignore +3 -0
  2. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/AGENTS.md +15 -4
  3. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/CHANGELOG.md +21 -1
  4. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/CLAUDE.md +15 -4
  5. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/LICENSE +10 -9
  6. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/PKG-INFO +6 -4
  7. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/README.md +5 -3
  8. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/architecture/caching.md +1 -1
  9. netbox_super_cli-1.0.2/docs/architecture/schema-loading.md +84 -0
  10. netbox_super_cli-1.0.2/docs/contributing/branching.md +110 -0
  11. netbox_super_cli-1.0.2/docs/contributing/release-process.md +94 -0
  12. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/getting-started/install.md +0 -2
  13. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/index.md +0 -2
  14. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/reference/config.md +2 -2
  15. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/mkdocs.yml +1 -0
  16. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/_version.py +1 -1
  17. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cache/store.py +45 -1
  18. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/app.py +12 -0
  19. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/globals.py +5 -1
  20. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/init_commands.py +21 -11
  21. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/runtime.py +1 -0
  22. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/config/models.py +1 -1
  23. netbox_super_cli-1.0.2/nsc/schema/source.py +208 -0
  24. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/pyproject.toml +1 -1
  25. netbox_super_cli-1.0.2/skills/netbox-super-cli/SKILL.md +291 -0
  26. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cache/test_store.py +39 -0
  27. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/test_app_smoke.py +53 -0
  28. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/test_init_commands.py +49 -4
  29. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/config/test_models.py +1 -1
  30. netbox_super_cli-1.0.2/tests/schema/test_source_ttl.py +361 -0
  31. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/uv.lock +1 -1
  32. netbox_super_cli-1.0.1/docs/architecture/schema-loading.md +0 -46
  33. netbox_super_cli-1.0.1/docs/contributing/release-process.md +0 -42
  34. netbox_super_cli-1.0.1/nsc/schema/source.py +0 -120
  35. netbox_super_cli-1.0.1/skills/netbox-super-cli/SKILL.md +0 -127
  36. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/.github/workflows/agents-md-sync.yml +0 -0
  37. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/.github/workflows/bench.yml +0 -0
  38. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/.github/workflows/claude.yml +0 -0
  39. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/.github/workflows/docs.yml +0 -0
  40. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/.github/workflows/e2e.yml +0 -0
  41. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/.github/workflows/lint.yml +0 -0
  42. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/.github/workflows/release.yml +0 -0
  43. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/.github/workflows/test.yml +0 -0
  44. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/.pre-commit-config.yaml +0 -0
  45. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/.python-version +0 -0
  46. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/architecture/command-generation.md +0 -0
  47. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/architecture/http-client.md +0 -0
  48. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/architecture/overview.md +0 -0
  49. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/contributing/adding-bundled-schemas.md +0 -0
  50. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/contributing/development.md +0 -0
  51. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/getting-started/concepts.md +0 -0
  52. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/getting-started/first-run.md +0 -0
  53. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/guides/ci-and-automation.md +0 -0
  54. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/guides/managing-profiles.md +0 -0
  55. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/guides/output-formats.md +0 -0
  56. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/guides/using-with-ai-agents.md +0 -0
  57. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/guides/working-with-plugins.md +0 -0
  58. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/guides/writes-and-safety.md +0 -0
  59. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/reference/cli.md +0 -0
  60. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/reference/exit-codes.md +0 -0
  61. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/docs/reference/schemas.md +0 -0
  62. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/justfile +0 -0
  63. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/__init__.py +0 -0
  64. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/__main__.py +0 -0
  65. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/aliases/__init__.py +0 -0
  66. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/aliases/resolver.py +0 -0
  67. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/auth/__init__.py +0 -0
  68. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/auth/verify.py +0 -0
  69. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/builder/__init__.py +0 -0
  70. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/builder/build.py +0 -0
  71. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cache/__init__.py +0 -0
  72. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/__init__.py +0 -0
  73. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/aliases_commands.py +0 -0
  74. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/cache_commands.py +0 -0
  75. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/commands_dump.py +0 -0
  76. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/config_commands.py +0 -0
  77. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/handlers.py +0 -0
  78. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/login_commands.py +0 -0
  79. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/profiles_commands.py +0 -0
  80. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/registration.py +0 -0
  81. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/skill_commands.py +0 -0
  82. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/writes/__init__.py +0 -0
  83. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/writes/apply.py +0 -0
  84. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/writes/bulk.py +0 -0
  85. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/writes/coercion.py +0 -0
  86. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/writes/confirmation.py +0 -0
  87. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/writes/input.py +0 -0
  88. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/cli/writes/preflight.py +0 -0
  89. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/config/__init__.py +0 -0
  90. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/config/loader.py +0 -0
  91. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/config/settings.py +0 -0
  92. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/config/writer.py +0 -0
  93. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/http/__init__.py +0 -0
  94. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/http/audit.py +0 -0
  95. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/http/client.py +0 -0
  96. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/http/errors.py +0 -0
  97. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/http/retry.py +0 -0
  98. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/model/__init__.py +0 -0
  99. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/model/command_model.py +0 -0
  100. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/output/__init__.py +0 -0
  101. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/output/csv_.py +0 -0
  102. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/output/errors.py +0 -0
  103. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/output/explain.py +0 -0
  104. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/output/flatten.py +0 -0
  105. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/output/headers.py +0 -0
  106. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/output/json_.py +0 -0
  107. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/output/jsonl.py +0 -0
  108. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/output/render.py +0 -0
  109. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/output/table.py +0 -0
  110. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/output/yaml_.py +0 -0
  111. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/schema/__init__.py +0 -0
  112. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/schema/hashing.py +0 -0
  113. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/schema/loader.py +0 -0
  114. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/schema/models.py +0 -0
  115. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/schemas/__init__.py +0 -0
  116. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/schemas/bundled/__init__.py +0 -0
  117. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/schemas/bundled/manifest.yaml +0 -0
  118. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/schemas/bundled/netbox-4.6.0-beta2.json.gz +0 -0
  119. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/nsc/skill/__init__.py +0 -0
  120. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/scripts/gen_docs.py +0 -0
  121. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/scripts/sync_agents_md.py +0 -0
  122. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/__init__.py +0 -0
  123. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/aliases/__init__.py +0 -0
  124. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/aliases/test_resolver.py +0 -0
  125. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/auth/__init__.py +0 -0
  126. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/auth/test_verify.py +0 -0
  127. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/benchmarks/__init__.py +0 -0
  128. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/benchmarks/test_startup.py +0 -0
  129. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/builder/__init__.py +0 -0
  130. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/builder/test_build.py +0 -0
  131. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/builder/test_default_columns.py +0 -0
  132. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/builder/test_redaction_marking.py +0 -0
  133. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/builder/test_request_body_shape.py +0 -0
  134. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cache/__init__.py +0 -0
  135. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cache/test_prune.py +0 -0
  136. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/__init__.py +0 -0
  137. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/test_aliases_commands.py +0 -0
  138. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/test_cache_commands.py +0 -0
  139. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/test_commands_dump.py +0 -0
  140. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/test_completion_smoke.py +0 -0
  141. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/test_config_commands.py +0 -0
  142. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/test_explain.py +0 -0
  143. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/test_handlers.py +0 -0
  144. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/test_login_commands.py +0 -0
  145. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/test_meta_subcommands_under_broken_config.py +0 -0
  146. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/test_ndjson_input.py +0 -0
  147. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/test_profiles_commands.py +0 -0
  148. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/test_registration.py +0 -0
  149. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/test_respx_integration.py +0 -0
  150. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/test_runtime.py +0 -0
  151. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/test_skill_commands.py +0 -0
  152. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/test_stdin_sniffer.py +0 -0
  153. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/test_writes_respx.py +0 -0
  154. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/writes/__init__.py +0 -0
  155. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/writes/test_apply.py +0 -0
  156. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/writes/test_bulk.py +0 -0
  157. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/writes/test_confirmation.py +0 -0
  158. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/writes/test_handler_helpers.py +0 -0
  159. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/writes/test_handlers_audit.py +0 -0
  160. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/writes/test_input.py +0 -0
  161. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/cli/writes/test_preflight.py +0 -0
  162. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/config/__init__.py +0 -0
  163. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/config/test_loader.py +0 -0
  164. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/config/test_writer_atomicity.py +0 -0
  165. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/config/test_writer_dotted_paths.py +0 -0
  166. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/config/test_writer_roundtrip.py +0 -0
  167. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/conftest.py +0 -0
  168. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/e2e/README.md +0 -0
  169. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/e2e/__init__.py +0 -0
  170. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/e2e/conftest.py +0 -0
  171. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/e2e/docker-compose.yml +0 -0
  172. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/e2e/test_audit_redaction.py +0 -0
  173. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/e2e/test_auth_error_envelope.py +0 -0
  174. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/e2e/test_bulk_create_with_loop_fallback.py +0 -0
  175. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/e2e/test_full_cycle.py +0 -0
  176. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/e2e/test_login.py +0 -0
  177. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/e2e/test_ndjson.py +0 -0
  178. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/e2e/test_preflight_blocks_apply.py +0 -0
  179. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/e2e/test_validation_error_envelope_from_netbox.py +0 -0
  180. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/e2e/wait_for_netbox.sh +0 -0
  181. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/fixtures/profiles/single_profile.yaml +0 -0
  182. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/fixtures/responses/auth_401.json +0 -0
  183. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/fixtures/responses/circuits_providers_list.json +0 -0
  184. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/fixtures/responses/dcim_devices_get.json +0 -0
  185. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/fixtures/responses/dcim_devices_list_p1.json +0 -0
  186. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/fixtures/responses/dcim_devices_list_p2.json +0 -0
  187. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/http/__init__.py +0 -0
  188. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/http/test_audit.py +0 -0
  189. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/http/test_audit_redaction.py +0 -0
  190. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/http/test_client.py +0 -0
  191. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/http/test_client_redaction_threading.py +0 -0
  192. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/http/test_errors.py +0 -0
  193. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/http/test_retry.py +0 -0
  194. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/model/__init__.py +0 -0
  195. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/model/test_command_model.py +0 -0
  196. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/model/test_request_body_shape.py +0 -0
  197. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/output/__init__.py +0 -0
  198. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/output/test_csv.py +0 -0
  199. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/output/test_errors.py +0 -0
  200. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/output/test_errors_aliases.py +0 -0
  201. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/output/test_explain.py +0 -0
  202. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/output/test_flatten.py +0 -0
  203. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/output/test_input_error_envelope.py +0 -0
  204. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/output/test_json.py +0 -0
  205. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/output/test_jsonl.py +0 -0
  206. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/output/test_render_dispatch.py +0 -0
  207. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/output/test_table.py +0 -0
  208. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/output/test_yaml.py +0 -0
  209. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/schema/__init__.py +0 -0
  210. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/schema/test_hashing.py +0 -0
  211. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/schema/test_loader.py +0 -0
  212. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/schema/test_models.py +0 -0
  213. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/schema/test_source.py +0 -0
  214. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/scripts/__init__.py +0 -0
  215. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/scripts/test_gen_docs.py +0 -0
  216. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/skill/__init__.py +0 -0
  217. {netbox_super_cli-1.0.1 → netbox_super_cli-1.0.2}/tests/skill/test_bundle.py +0 -0
@@ -35,3 +35,6 @@ docs/superpowers/
35
35
 
36
36
  # mkdocs
37
37
  site/
38
+
39
+ # git worktrees
40
+ .worktrees/
@@ -7,7 +7,7 @@
7
7
 
8
8
  # Working on netbox-super-cli (for AI agents)
9
9
 
10
- This is the contributor guide for AI agents (and humans!) modifying this repo. The end-user-facing AI guide is the bundled Skill at `skills/netbox-super-cli/SKILL.md` (added in Phase 5).
10
+ This is the contributor guide for AI agents (and humans!) modifying this repo. The end-user-facing AI guide is the bundled Skill at `skills/netbox-super-cli/SKILL.md`.
11
11
 
12
12
  ## Architecture cheat sheet
13
13
 
@@ -15,10 +15,13 @@ This is the contributor guide for AI agents (and humans!) modifying this repo. T
15
15
  - `nsc/model/` — the normalized command tree (data only, framework-free). The "brain".
16
16
  - `nsc/builder/` — converts a parsed schema into a `CommandModel`.
17
17
  - `nsc/cli/` — the Typer app; consumes a `CommandModel`.
18
- - `nsc/http/` — thin httpx wrapper (Phase 2+).
19
- - `nsc/output/` — formatters (Phase 2+).
20
- - `nsc/config/` — config loader + Pydantic models (Phase 1 has a minimal version).
18
+ - `nsc/http/` — thin httpx wrapper: auth, retries, audit log.
19
+ - `nsc/output/` — formatters (table/json/jsonl/yaml/csv) + error envelope.
20
+ - `nsc/config/` — config loader + Pydantic models + ruamel.yaml round-trip writer.
21
21
  - `nsc/cache/` — disk cache for generated command-models.
22
+ - `nsc/auth/` — login verification helpers (pre-flight probes, token rotate).
23
+ - `nsc/aliases/` — curated alias resolver (`ls`, `get`, `rm`, `search`). Framework-free.
24
+ - `nsc/skill/` — bundle-path helper for the portable `SKILL.md` shipped in the wheel.
22
25
  - `nsc/schemas/bundled/` — versioned NetBox OpenAPI snapshots, fallback when offline.
23
26
 
24
27
  The hard rule: **`nsc/model/` imports nothing from `nsc/cli/`, `nsc/http/`, or any framework.** If you need to add a dependency to `model/`, you're probably solving the wrong problem.
@@ -39,6 +42,14 @@ The hard rule: **`nsc/model/` imports nothing from `nsc/cli/`, `nsc/http/`, or a
39
42
  - TDD: write the failing test first.
40
43
  - No comments on what code does; only on non-obvious *why*.
41
44
 
45
+ ## Branching
46
+
47
+ `main` is protected — direct pushes are rejected. All work happens on
48
+ short-lived feature branches (`fix/<slug>`, `feat/<slug>`, `docs/<slug>`,
49
+ …), opens a PR against `main`, passes required CI checks, and squash-merges.
50
+ Releases are *tags* on `main`, not branches. Full convention:
51
+ [`docs/contributing/branching.md`](docs/contributing/branching.md).
52
+
42
53
  ## Where the design lives
43
54
 
44
55
  - `docs/superpowers/specs/2026-04-30-netbox-super-cli-design.md` — the full design.
@@ -2,7 +2,27 @@
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
5
+ ## v1.0.2 — 2026-05-07
6
+
7
+ Second patch release. Headline change is the schema TTL fast-path (issue #34), which eliminates the per-invocation `GET /api/schema/` round-trip on warm caches. Also includes a small `nsc init` UX addition (verify_ssl prompt) and the documentation pass that landed since v1.0.1.
8
+
9
+ ### Added
10
+
11
+ - **Schema TTL fast-path** (issue #34). `nsc` now skips the per-invocation `GET /api/schema/` round-trip when a sidecar-validated cache entry is fresh. Freshness is tracked in `~/.nsc/cache/<profile>/<hash>.meta.json` (an explicit `fetched_at` timestamp), not file mtime — so `touch`, backup-restore, or `cp -p` can't fake freshness, and clocks that jumped forward then back are rejected (>60s skew distrusted).
12
+ - **`nsc --refresh-schema <subcmd>`** — one-shot forced refresh that bypasses the TTL even on `daily`/`weekly`/`manual` policies. Use after a NetBox upgrade to pick up a new schema immediately without changing config.
13
+ - Atomic cache writes — `CacheStore.save` now writes via temp-file + `os.replace`, so a concurrent `nsc` reader can never observe a partial cache file.
14
+ - **`nsc init` prompts for SSL verification** (issue #22). The first-run wizard now asks `Verify SSL certificates?` (defaults `Y`) after URL entry. Accepting the default keeps the config minimal (no `verify_ssl` key written); answering `n` writes `verify_ssl: false` into the profile block.
15
+
16
+ ### Changed
17
+
18
+ - **Default `defaults.schema_refresh` is now `daily`** (was `on-hash-change`). This is the user-visible behaviour change behind the fast-path: under the new default, `nsc` trusts a cached schema for 24h. **If you need the v1.0.1 behaviour** (re-fetch every invocation to detect a schema change immediately), set `defaults.schema_refresh: on-hash-change` in `~/.nsc/config.yaml`. To force a one-shot refresh under any policy, prepend `--refresh-schema` to the command. Existing configs with an explicit `schema_refresh` value are unaffected.
19
+ - Cache files written before this release have no sidecar and will be treated as stale on first invocation after upgrade — `nsc` refetches once, writes the sidecar, and the fast-path is active from there.
20
+
21
+ ### Documentation
22
+
23
+ - LICENSE file normalized byte-for-byte to the apache.org canonical Apache 2.0 text (issue #18).
24
+ - Trunk-based branching guide added at `docs/contributing/branching.md`; branch protection enabled on `main` (PR #28).
25
+ - Bundled Skill (`skills/netbox-super-cli/SKILL.md`) gained a NetBox device type library section (PR #27).
6
26
 
7
27
  ## v1.0.1 — 2026-05-06
8
28
 
@@ -1,6 +1,6 @@
1
1
  # Working on netbox-super-cli (for AI agents)
2
2
 
3
- This is the contributor guide for AI agents (and humans!) modifying this repo. The end-user-facing AI guide is the bundled Skill at `skills/netbox-super-cli/SKILL.md` (added in Phase 5).
3
+ This is the contributor guide for AI agents (and humans!) modifying this repo. The end-user-facing AI guide is the bundled Skill at `skills/netbox-super-cli/SKILL.md`.
4
4
 
5
5
  ## Architecture cheat sheet
6
6
 
@@ -8,10 +8,13 @@ This is the contributor guide for AI agents (and humans!) modifying this repo. T
8
8
  - `nsc/model/` — the normalized command tree (data only, framework-free). The "brain".
9
9
  - `nsc/builder/` — converts a parsed schema into a `CommandModel`.
10
10
  - `nsc/cli/` — the Typer app; consumes a `CommandModel`.
11
- - `nsc/http/` — thin httpx wrapper (Phase 2+).
12
- - `nsc/output/` — formatters (Phase 2+).
13
- - `nsc/config/` — config loader + Pydantic models (Phase 1 has a minimal version).
11
+ - `nsc/http/` — thin httpx wrapper: auth, retries, audit log.
12
+ - `nsc/output/` — formatters (table/json/jsonl/yaml/csv) + error envelope.
13
+ - `nsc/config/` — config loader + Pydantic models + ruamel.yaml round-trip writer.
14
14
  - `nsc/cache/` — disk cache for generated command-models.
15
+ - `nsc/auth/` — login verification helpers (pre-flight probes, token rotate).
16
+ - `nsc/aliases/` — curated alias resolver (`ls`, `get`, `rm`, `search`). Framework-free.
17
+ - `nsc/skill/` — bundle-path helper for the portable `SKILL.md` shipped in the wheel.
15
18
  - `nsc/schemas/bundled/` — versioned NetBox OpenAPI snapshots, fallback when offline.
16
19
 
17
20
  The hard rule: **`nsc/model/` imports nothing from `nsc/cli/`, `nsc/http/`, or any framework.** If you need to add a dependency to `model/`, you're probably solving the wrong problem.
@@ -32,6 +35,14 @@ The hard rule: **`nsc/model/` imports nothing from `nsc/cli/`, `nsc/http/`, or a
32
35
  - TDD: write the failing test first.
33
36
  - No comments on what code does; only on non-obvious *why*.
34
37
 
38
+ ## Branching
39
+
40
+ `main` is protected — direct pushes are rejected. All work happens on
41
+ short-lived feature branches (`fix/<slug>`, `feat/<slug>`, `docs/<slug>`,
42
+ …), opens a PR against `main`, passes required CI checks, and squash-merges.
43
+ Releases are *tags* on `main`, not branches. Full convention:
44
+ [`docs/contributing/branching.md`](docs/contributing/branching.md).
45
+
35
46
  ## Where the design lives
36
47
 
37
48
  - `docs/superpowers/specs/2026-04-30-netbox-super-cli-design.md` — the full design.
@@ -1,3 +1,4 @@
1
+
1
2
  Apache License
2
3
  Version 2.0, January 2004
3
4
  http://www.apache.org/licenses/
@@ -32,10 +33,10 @@
32
33
  not limited to compiled object code, generated documentation,
33
34
  and conversions to other media types.
34
35
 
35
- "Work" shall mean the work of authorship, whether in Source or Object
36
- form, made available under the License, as indicated by a copyright
37
- notice that is included in or attached to the work (an example is
38
- provided in the Appendix below).
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
39
40
 
40
41
  "Derivative Works" shall mean any work, whether in Source or Object
41
42
  form, that is based on (or derived from) the Work and for which the
@@ -155,7 +156,7 @@
155
156
  unless required by applicable law (such as deliberate and grossly
156
157
  negligent acts) or agreed to in writing, shall any Contributor be
157
158
  liable to You for damages, including any direct, indirect, special,
158
- incidental, or exemplary damages of any character arising as a
159
+ incidental, or consequential damages of any character arising as a
159
160
  result of this License or out of the use or inability to use the
160
161
  Work (including but not limited to damages for loss of goodwill,
161
162
  work stoppage, computer failure or malfunction, or any and all
@@ -163,12 +164,12 @@
163
164
  has been advised of the possibility of such damages.
164
165
 
165
166
  9. Accepting Warranty or Additional Liability. While redistributing
166
- the Work or Derivative Works thereof, you may choose to offer,
167
+ the Work or Derivative Works thereof, You may choose to offer,
167
168
  and charge a fee for, acceptance of support, warranty, indemnity,
168
169
  or other liability obligations and/or rights consistent with this
169
- License. However, in accepting such obligations, you may act only
170
- on your own behalf and on your sole responsibility, not on behalf
171
- of any other Contributor, and only if you agree to indemnify,
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
172
173
  defend, and hold each Contributor harmless for any liability
173
174
  incurred by, or claims asserted against, such Contributor by reason
174
175
  of your accepting any such warranty or additional liability.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: netbox-super-cli
3
- Version: 1.0.1
3
+ Version: 1.0.2
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: Issues, https://github.com/thomaschristory/netbox-super-cli/issues
@@ -38,13 +38,15 @@ A Python CLI for [NetBox](https://netbox.dev/) that builds its command tree dyna
38
38
  - **Safe by default.** POST/PATCH/PUT/DELETE preview as dry-runs unless you pass `--apply`.
39
39
  - **Agent-friendly.** Deterministic command shape, machine-readable JSON output, stable error envelope with documented exit codes.
40
40
 
41
- ## Install (preview)
41
+ ## Install
42
42
 
43
43
  ```
44
44
  uv tool install netbox-super-cli
45
+ # or, with pipx:
46
+ pipx install netbox-super-cli
45
47
  ```
46
48
 
47
- Not on PyPI yet; install from source:
49
+ Or from source:
48
50
  ```
49
51
  git clone https://github.com/thomaschristory/netbox-super-cli
50
52
  cd netbox-super-cli
@@ -112,7 +114,7 @@ Stdin is sniffed from the first 512 bytes (first non-whitespace byte plus a one-
112
114
  - HTTP headers in the `SENSITIVE_HEADERS` set (e.g. `Authorization`, `X-API-Key`) — replaced with `"<redacted>"`.
113
115
  - Request-body fields whose OpenAPI definition has `format: password` OR whose name (case-insensitive) is one of: `password`, `secret`, `token`, `api_key`, `apikey`, `private_key`, `passphrase`, `client_secret`. Nested fields and arrays of objects are walked recursively.
114
116
 
115
- The wire body sent to NetBox is **not** redacted — only the audit log. A failed write still records the redacted body; redaction is irreversible. Treat `audit.jsonl` like a verbose application log: gate it behind your home-directory permissions and rotate / archive accordingly. A "redact everything" mode is deferred to Phase 5+.
117
+ The wire body sent to NetBox is **not** redacted — only the audit log. A failed write still records the redacted body; redaction is irreversible. Treat `audit.jsonl` like a verbose application log: gate it behind your home-directory permissions and rotate / archive accordingly. A "redact everything" mode is on the post-v1.0 roadmap.
116
118
 
117
119
  ## Output and errors
118
120
 
@@ -11,13 +11,15 @@ A Python CLI for [NetBox](https://netbox.dev/) that builds its command tree dyna
11
11
  - **Safe by default.** POST/PATCH/PUT/DELETE preview as dry-runs unless you pass `--apply`.
12
12
  - **Agent-friendly.** Deterministic command shape, machine-readable JSON output, stable error envelope with documented exit codes.
13
13
 
14
- ## Install (preview)
14
+ ## Install
15
15
 
16
16
  ```
17
17
  uv tool install netbox-super-cli
18
+ # or, with pipx:
19
+ pipx install netbox-super-cli
18
20
  ```
19
21
 
20
- Not on PyPI yet; install from source:
22
+ Or from source:
21
23
  ```
22
24
  git clone https://github.com/thomaschristory/netbox-super-cli
23
25
  cd netbox-super-cli
@@ -85,7 +87,7 @@ Stdin is sniffed from the first 512 bytes (first non-whitespace byte plus a one-
85
87
  - HTTP headers in the `SENSITIVE_HEADERS` set (e.g. `Authorization`, `X-API-Key`) — replaced with `"<redacted>"`.
86
88
  - Request-body fields whose OpenAPI definition has `format: password` OR whose name (case-insensitive) is one of: `password`, `secret`, `token`, `api_key`, `apikey`, `private_key`, `passphrase`, `client_secret`. Nested fields and arrays of objects are walked recursively.
87
89
 
88
- The wire body sent to NetBox is **not** redacted — only the audit log. A failed write still records the redacted body; redaction is irreversible. Treat `audit.jsonl` like a verbose application log: gate it behind your home-directory permissions and rotate / archive accordingly. A "redact everything" mode is deferred to Phase 5+.
90
+ The wire body sent to NetBox is **not** redacted — only the audit log. A failed write still records the redacted body; redaction is irreversible. Treat `audit.jsonl` like a verbose application log: gate it behind your home-directory permissions and rotate / archive accordingly. A "redact everything" mode is on the post-v1.0 roadmap.
89
91
 
90
92
  ## Output and errors
91
93
 
@@ -26,7 +26,7 @@ one-line "schema changed, regenerating…" notice on stderr.
26
26
 
27
27
  ## Cleaning up
28
28
 
29
- `nsc cache prune` (Phase 5a) handles three classes of orphan:
29
+ `nsc cache prune` handles three classes of orphan:
30
30
 
31
31
  1. Profile directories not in `~/.nsc/config.yaml` (e.g., a removed profile).
32
32
  2. `<schema_hash>.json` files inside an active profile whose hash no longer
@@ -0,0 +1,84 @@
1
+ # Schema loading
2
+
3
+ `nsc/schema/` fetches and parses the OpenAPI document.
4
+
5
+ ## Resolution order
6
+
7
+ Highest priority first, given the active `defaults.schema_refresh` policy
8
+ and an optional `--refresh-schema` override:
9
+
10
+ 1. `--schema <path-or-url>` — one-shot override. Always wins; never
11
+ consults the TTL fast-path or the network.
12
+ 2. **TTL fast-path.** If the policy is `daily`, `weekly`, or `manual` and
13
+ the newest sidecar-validated cache entry for the active profile is
14
+ fresher than the policy's TTL, `nsc` returns it directly with no HTTP
15
+ round-trip. Skipped when `--refresh-schema` is passed (or the policy
16
+ is `on-hash-change`).
17
+ 3. Live fetch from the active profile's `schema_url` (explicit) or
18
+ `{profile.url}/api/schema/?format=json`. The fetched body is hashed;
19
+ if a cache file already exists at that hash it's loaded directly,
20
+ otherwise the command-model is rebuilt and saved.
21
+ 4. On fetch failure: any cached entry for the profile (warns once on
22
+ stderr).
23
+ 5. Bundled snapshot at `nsc/schemas/bundled/netbox-<closest-version>.json`
24
+ (shipped in the wheel) — last-resort offline fallback.
25
+
26
+ ## Hashing
27
+
28
+ The cache key is `sha256` of the canonicalized schema body (JSON
29
+ re-serialized with sorted keys, no whitespace). Cosmetic changes to the
30
+ upstream schema (whitespace, key order) don't bust the cache, but any
31
+ semantic change (new endpoint, changed field) does.
32
+
33
+ ## Cache layout
34
+
35
+ Each profile has a directory under `~/.nsc/cache/<profile>/` containing,
36
+ per schema hash:
37
+
38
+ - `<hash>.json` — the generated `CommandModel`. Loaded via
39
+ `CacheStore.load`, which re-verifies that the file's embedded
40
+ `schema_hash` matches the filename — so a tampered or copied JSON
41
+ file is rejected.
42
+ - `<hash>.meta.json` — a sidecar with `{"fetched_at": <epoch_seconds>}`.
43
+ Drives the TTL fast-path. Written atomically alongside the cache file
44
+ via temp-file + `os.replace`.
45
+
46
+ A sidecar dated more than 60s in the future (clock skew or tampering)
47
+ is rejected. A cache entry without its sidecar is treated as stale —
48
+ that's the upgrade path for caches written before sidecars existed.
49
+
50
+ ## Offline behavior
51
+
52
+ - Live schema unreachable + cache present → use cache, warn once on
53
+ stderr.
54
+ - Live schema unreachable + no cache → fall back to the closest bundled
55
+ version, warn loudly.
56
+ - All such errors include a remediation hint pointing at
57
+ `--refresh-schema` for once the instance is reachable again.
58
+
59
+ ## Refresh modes
60
+
61
+ In `~/.nsc/config.yaml`:
62
+
63
+ ```yaml
64
+ defaults:
65
+ schema_refresh: daily # default since the v1.0.2 release line
66
+ ```
67
+
68
+ | Value | TTL | Behaviour |
69
+ |------------------|--------|-----------------------------------------------------------------|
70
+ | `daily` | 24h | Default. Trust a fresh cache; re-fetch once a day. |
71
+ | `weekly` | 7d | Trust longer; suitable for stable NetBox deployments. |
72
+ | `manual` | ∞ | Never auto-invalidate. Use `--refresh-schema` to update. |
73
+ | `on-hash-change` | 0 | v1.0.1 behaviour: re-fetch every invocation, compare hashes. |
74
+
75
+ Use `nsc --refresh-schema <subcommand>` to force a one-shot refresh
76
+ that bypasses the TTL fast-path under any policy.
77
+
78
+ ## When you change NetBox versions
79
+
80
+ The hash changes → next invocation that bypasses the fast-path
81
+ regenerates the model. Under `daily` (the default) you may need to
82
+ prepend `--refresh-schema` to your first post-upgrade invocation, or
83
+ wait up to 24h. The old `<old_hash>.json` (and its sidecar) become
84
+ orphaned and get cleaned by `nsc cache prune`.
@@ -0,0 +1,110 @@
1
+ # Branching and merging
2
+
3
+ `netbox-super-cli` follows trunk-based development with short-lived
4
+ feature branches. There is exactly one long-lived branch — `main` —
5
+ and it is always releasable.
6
+
7
+ ## The branches
8
+
9
+ - **`main`** — the integration branch. Every accepted change lands here.
10
+ Each commit on `main` is a candidate for the next release.
11
+ - **Feature branches** — short-lived, named for the change they carry.
12
+ Created from `main`, deleted on merge.
13
+ - **Tags** (`vX.Y.Z`) — the release artifact. A tag points at a commit
14
+ on `main`; `release.yml` builds and publishes from the tagged commit.
15
+
16
+ There is no separate "release branch". A release is a *tagged commit
17
+ on `main`*, not a branch. Multiple unreleased commits accumulate on
18
+ `main` between tags; tagging snapshots them into a release.
19
+
20
+ ## Naming convention
21
+
22
+ Feature branches use a `<type>/<short-slug>` prefix matching the
23
+ [Conventional Commit](https://www.conventionalcommits.org/) types:
24
+
25
+ - `feat/<slug>` — new feature.
26
+ - `fix/<slug>` — bug fix.
27
+ - `docs/<slug>` — documentation only.
28
+ - `refactor/<slug>` — internal restructure, no behaviour change.
29
+ - `chore/<slug>` — tooling, dependency bumps, release prep.
30
+ - `ci/<slug>` — workflow / CI changes.
31
+ - `test/<slug>` — test-only changes.
32
+
33
+ Agent-generated branches may use the existing `claude/issue-<n>-<date>`
34
+ pattern; the prefix isn't load-bearing as long as the branch is
35
+ short-lived.
36
+
37
+ ## Lifecycle of a change
38
+
39
+ 1. Branch from latest `main`:
40
+ ```sh
41
+ git checkout main && git pull
42
+ git checkout -b fix/<slug>
43
+ ```
44
+ 2. Commit using Conventional Commits (`fix(scope): subject`).
45
+ 3. Push and open a PR against `main`. CI runs.
46
+ 4. Once green and (if applicable) reviewed, **squash-merge** to `main`.
47
+ Squashing keeps `main` one-commit-per-PR — easy to scan, easy to
48
+ revert.
49
+ 5. Delete the feature branch (`gh pr merge --delete-branch`, or the
50
+ "Delete branch" button on the PR).
51
+
52
+ The squashed commit subject follows `<type>(scope): subject (#N)` —
53
+ matching the existing convention seen on PRs #8, #10, #26.
54
+
55
+ ## Branch protection on `main`
56
+
57
+ `main` is protected. The exact rules are configured via the GitHub
58
+ branch-protection API; the current policy is:
59
+
60
+ - **No direct pushes.** Every change goes through a pull request.
61
+ - **Required status checks** must pass before merge:
62
+ - `lint`
63
+ - `test (ubuntu-latest, 3.12)`
64
+ - **Force pushes blocked.**
65
+ - **Branch deletion blocked.**
66
+ - **Administrators are not exempt.** Even repo owners go through PRs.
67
+
68
+ To inspect or change the rule:
69
+
70
+ ```sh
71
+ gh api repos/:owner/:repo/branches/main/protection
72
+ gh api repos/:owner/:repo/branches/main/protection -X PUT --input rules.json
73
+ ```
74
+
75
+ If a status-check job is renamed in CI, update `contexts` in the
76
+ protection rule the same day — otherwise PRs will hang waiting for a
77
+ check that no longer runs.
78
+
79
+ ## Releases vs. branches
80
+
81
+ Releases are a *separate* concern from branching:
82
+
83
+ - Release prep (CHANGELOG roll, version bumps in `pyproject.toml` and
84
+ `nsc/_version.py`) happens on a `chore/release-X.Y.Z` branch.
85
+ - Open a PR for the release prep, merge to `main`, **then** tag the
86
+ resulting merge commit:
87
+ ```sh
88
+ git checkout main && git pull
89
+ git tag -a vX.Y.Z -m "vX.Y.Z"
90
+ git push origin vX.Y.Z
91
+ ```
92
+ - The tag triggers `release.yml`, which builds the wheel + sdist and
93
+ publishes to PyPI.
94
+ - See [`release-process.md`](release-process.md) for the full checklist.
95
+
96
+ We do **not** maintain release branches (`release/v1.x`) at this time.
97
+ Milestones (e.g. `v1.0.2`, `v1.1.0`) track *what's planned* for which
98
+ release without forking the codebase.
99
+
100
+ ## Why no long-lived release branches?
101
+
102
+ For a single-trunk project, release branches add merge overhead
103
+ (every fix needs two homes) without benefit. A milestone tells us
104
+ "this issue is scoped to v1.0.2"; the actual code change lives on
105
+ `main` and ships when we tag.
106
+
107
+ The day we need to support v1.x and v2.x simultaneously, we'll cut
108
+ `release/v1.x` from the last v1.* tag and start cherry-picking
109
+ qualifying fixes into it. Until then, `main` is the only place code
110
+ lives.
@@ -0,0 +1,94 @@
1
+ # Release process
2
+
3
+ `nsc` follows [Semantic Versioning](https://semver.org/) from v1.0.0 onward.
4
+ Releases are tag-driven: `release.yml` fires on `v*.*.*` tag pushes and
5
+ publishes to PyPI via trusted publishing (no API tokens).
6
+
7
+ A release is a **tagged commit on `main`**, not a separate branch — see
8
+ [Branching and merging](branching.md) for the trunk-based workflow this
9
+ process assumes. Release prep (CHANGELOG roll + version bumps) happens
10
+ on a `chore/release-X.Y.Z` feature branch, gets PR-merged into `main`,
11
+ and only then is `vX.Y.Z` tagged on the resulting merge commit.
12
+
13
+ ## Normal release checklist
14
+
15
+ 1. Full unit suite green: `just test`.
16
+ 2. Lint clean: `just lint`.
17
+ 3. Bench median <300 ms: `just bench`.
18
+ 4. E2E green (requires Docker): `just e2e`.
19
+ 5. Roll `CHANGELOG.md`: move `[Unreleased]` to `[vX.Y.Z] — YYYY-MM-DD`.
20
+ 6. Bump `pyproject.toml` `[project].version` and `nsc/_version.py` `__version__`
21
+ to match the tag.
22
+ 7. Verify all issues attached to the matching
23
+ [GitHub milestone](https://github.com/thomaschristory/netbox-super-cli/milestones)
24
+ are resolved or deferred (don't close the milestone yet — that happens
25
+ after publish, see below).
26
+ 8. Commit: `git commit -m "chore(release): X.Y.Z"`.
27
+ 9. Annotate and push: `git tag -a vX.Y.Z -m "vX.Y.Z" && git push origin main vX.Y.Z`.
28
+ 10. Watch `release.yml` publish the wheel and create the GitHub Release.
29
+ 11. Once PyPI shows the new version and the GitHub Release is live, close
30
+ the milestone and open the next one — see the next section for the
31
+ exact `gh api` invocations.
32
+
33
+ ## GitHub milestones convention
34
+
35
+ Each planned release has a milestone named after its version (e.g., `v1.1.0`).
36
+ Issues and PRs are triaged to a milestone when they are scoped to a specific
37
+ release. Milestones don't gate CI — they're a planning aid that surfaces
38
+ what's queued for which version.
39
+
40
+ - Milestone name: `vX.Y.Z` (matches the git tag exactly).
41
+ - An open milestone with no due date means "planned but not scheduled".
42
+ - The `main` branch is always releasable; milestones don't block merges.
43
+
44
+ **Once a release is published**, close its milestone and open the next one.
45
+ This is step 11 of the release checklist; the exact commands are:
46
+
47
+ 1. Bump or close any open issues left in the just-shipped milestone —
48
+ either move them to the next milestone or drop them to the backlog.
49
+ 2. Close the milestone:
50
+ ```sh
51
+ gh api repos/:owner/:repo/milestones/<N> -X PATCH -f state=closed
52
+ ```
53
+ 3. Open the next one:
54
+ ```sh
55
+ gh api repos/:owner/:repo/milestones -f title='v<next>' -f state=open
56
+ ```
57
+ For a patch release, increment the patch number; for a minor/major,
58
+ pick whatever's next based on what's queued.
59
+ 4. Leave the new milestone otherwise empty — issues get attached as they're
60
+ triaged.
61
+
62
+ This keeps a milestone always available to file new issues against without
63
+ having to think about it mid-bug-report.
64
+
65
+ ## Patch releases (bug fixes)
66
+
67
+ Patch bumps (`Z` increment) follow the same checklist. Because they contain
68
+ only bug fixes, the E2E run can be skipped if the fix is confined to a code
69
+ path not exercised by the E2E suite — but running it is still recommended.
70
+
71
+ ## Minor / major releases
72
+
73
+ Minor (`Y`) or major (`X`) bumps follow the full checklist. Before tagging,
74
+ open a tracking issue or milestone for any follow-on items deferred from the
75
+ release.
76
+
77
+ ## Hot-fixing a tagged release
78
+
79
+ Never amend a tagged commit. Increment the patch component (e.g.,
80
+ `v1.0.1` → `v1.0.2`), cut a fresh patch release with the fix, and document
81
+ it in `CHANGELOG.md` under a new `[vX.Y.Z]` entry for the new version.
82
+
83
+ ## Versioning policy
84
+
85
+ From v1.0.0 onward:
86
+
87
+ - `PATCH` — backwards-compatible bug fixes.
88
+ - `MINOR` — new backwards-compatible features or CLI commands.
89
+ - `MAJOR` — breaking changes to the error envelope, exit codes, or config schema.
90
+
91
+ The version in `pyproject.toml`, `nsc/_version.py`, and the git tag must
92
+ always agree. `release.yml` validates the tag against `nsc/_version.py`
93
+ before publishing; `pyproject.toml` is not currently checked, so keep it
94
+ in sync manually as part of the release commit.
@@ -15,8 +15,6 @@ pipx install netbox-super-cli
15
15
  uv tool install netbox-super-cli
16
16
  ```
17
17
 
18
- > **Phase 5b note:** the PyPI release lands in Phase 5d. Until then, install from source (see below).
19
-
20
18
  Verify the install:
21
19
 
22
20
  ```sh
@@ -4,8 +4,6 @@ Dynamic NetBox CLI driven by the live OpenAPI schema. The same `nsc` binary work
4
4
  against any NetBox version (4.4+) and exposes plugin-provided endpoints automatically
5
5
  because the schema — not hand-written code — defines the surface.
6
6
 
7
- > **Status:** Phase 5b. v1.0.0 publish lands in 5d. Until then, install from source.
8
-
9
7
  ## Why nsc
10
8
 
11
9
  - **Plugins just work.** New endpoints from any installed plugin appear as commands automatically.
@@ -11,7 +11,7 @@ All fields below describe `~/.nsc/config.yaml`.
11
11
  |---|---|---|
12
12
  | `default_profile` | `str | None` | `None` |
13
13
  | `profiles` | `dict[str, Profile]` | `{}` |
14
- | `defaults` | `<class 'Defaults'>` | `Defaults(output=<OutputFormat.TABLE: 'table'>, page_size=50, timeout=30.0, schema_refresh=<SchemaRefresh.ON_HASH_CHANGE: 'on-hash-change'>)` |
14
+ | `defaults` | `<class 'Defaults'>` | `Defaults(output=<OutputFormat.TABLE: 'table'>, page_size=50, timeout=30.0, schema_refresh=<SchemaRefresh.DAILY: 'daily'>)` |
15
15
  | `columns` | `dict[str, dict[str, list[str]]]` | `{}` |
16
16
 
17
17
  ## `Profile`
@@ -32,4 +32,4 @@ All fields below describe `~/.nsc/config.yaml`.
32
32
  | `output` | `<enum 'OutputFormat'>` | `<OutputFormat.TABLE: 'table'>` |
33
33
  | `page_size` | `<class 'int'>` | `50` |
34
34
  | `timeout` | `<class 'float'>` | `30.0` |
35
- | `schema_refresh` | `<enum 'SchemaRefresh'>` | `<SchemaRefresh.ON_HASH_CHANGE: 'on-hash-change'>` |
35
+ | `schema_refresh` | `<enum 'SchemaRefresh'>` | `<SchemaRefresh.DAILY: 'daily'>` |
@@ -75,5 +75,6 @@ nav:
75
75
  - Caching: architecture/caching.md
76
76
  - Contributing:
77
77
  - Development: contributing/development.md
78
+ - Branching and merging: contributing/branching.md
78
79
  - Release process: contributing/release-process.md
79
80
  - Adding bundled schemas: contributing/adding-bundled-schemas.md
@@ -1,3 +1,3 @@
1
1
  """Single source of truth for the package version."""
2
2
 
3
- __version__ = "1.0.1"
3
+ __version__ = "1.0.2"