@ngocsangairvds/vsaf 3.1.27 → 3.2.1

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 (303) hide show
  1. package/package.json +2 -2
  2. package/src/global.js +70 -10
  3. package/tools/skills/vds-scripts-skill/.openskills.json +6 -0
  4. package/tools/skills/vds-scripts-skill/QUALITY.md +44 -0
  5. package/tools/skills/vds-scripts-skill/SKILL.md +135 -0
  6. package/tools/skills/vds-scripts-skill/references/audit-commands.md +171 -0
  7. package/tools/skills/vds-scripts-skill/references/capability-index.md +34 -0
  8. package/tools/skills/vds-scripts-skill/references/development-commands.md +12 -0
  9. package/tools/skills/vds-scripts-skill/references/google-sheets.md +73 -0
  10. package/tools/skills/vds-scripts-skill/references/integration-commands.md +17 -0
  11. package/tools/skills/vds-scripts-skill/references/platform-bootstrap.md +31 -0
  12. package/tools/skills/vds-scripts-skill/references/specialist-routing.md +14 -0
  13. package/tools/skills/vds-scripts-skill/references/validation-commands.md +15 -0
  14. package/tools/skills/vsaf-build/SKILL.md +32 -2
  15. package/tools/skills/vsaf-ship/SKILL.md +41 -10
  16. package/tools/skills/vsaf-test/SKILL.md +8 -0
  17. package/tools/vds-scripts/.mcp.json +11 -0
  18. package/tools/vds-scripts/.secrets.baseline +133 -0
  19. package/tools/vds-scripts/AGENTS.md +152 -0
  20. package/tools/vds-scripts/CLAUDE.md +101 -0
  21. package/tools/vds-scripts/CLI_COMMAND_OPTIMIZATION.md +156 -0
  22. package/tools/vds-scripts/PACKAGE_P125B_IMPLEMENTATION_SUMMARY.md +131 -0
  23. package/tools/vds-scripts/PROJECT_COMPLETION_SUMMARY.md +45 -0
  24. package/tools/vds-scripts/README.md +97 -0
  25. package/tools/vds-scripts/bitbucket_manifest_mapping.toml +34 -0
  26. package/tools/vds-scripts/bitbucket_orchestrator/ARCHITECTURE_ANALYSIS.md +258 -0
  27. package/tools/vds-scripts/bitbucket_orchestrator/BITBUCKET_API_PRACTICES.md +393 -0
  28. package/tools/vds-scripts/bitbucket_orchestrator/EVALUATION_REPORT.md +61 -0
  29. package/tools/vds-scripts/bitbucket_orchestrator/FEATURES.md +908 -0
  30. package/tools/vds-scripts/bitbucket_orchestrator/README.md +687 -0
  31. package/tools/vds-scripts/bitbucket_orchestrator/pyproject.toml +40 -0
  32. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/__init__.py +20 -0
  33. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/async_client.py +657 -0
  34. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/cli.py +2108 -0
  35. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/client.py +2534 -0
  36. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/config.py +171 -0
  37. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/errors.py +67 -0
  38. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/factory.py +185 -0
  39. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/protocols.py +244 -0
  40. package/tools/vds-scripts/bitbucket_orchestrator/tests/__init__.py +8 -0
  41. package/tools/vds-scripts/bitbucket_orchestrator/tests/conftest.py +65 -0
  42. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_advanced_search.py +151 -0
  43. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_async_client.py +546 -0
  44. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_branch_permissions.py +145 -0
  45. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_cli.py +115 -0
  46. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client.py +157 -0
  47. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_branch_conditions.py +79 -0
  48. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_code_advanced.py +163 -0
  49. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_code_file.py +32 -0
  50. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_deployment_environments.py +194 -0
  51. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_issues.py +164 -0
  52. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_pipelines_advanced.py +179 -0
  53. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_pr_blockers.py +119 -0
  54. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_repository_variables.py +156 -0
  55. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_code.py +98 -0
  56. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_code_advanced.py +282 -0
  57. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_code_insights.py +335 -0
  58. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_conditions.py +147 -0
  59. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_config.py +131 -0
  60. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_deployment_env.py +352 -0
  61. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_factory.py +371 -0
  62. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_fork_operations.py +204 -0
  63. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_issue_cli.py +261 -0
  64. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_pipeline_advanced.py +270 -0
  65. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_pr_blocker.py +204 -0
  66. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_protocols.py +334 -0
  67. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_repo_settings.py +343 -0
  68. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_repo_variables.py +270 -0
  69. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_webhooks.py +189 -0
  70. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_workspace.py +233 -0
  71. package/tools/vds-scripts/bitbucket_orchestrator/uv.lock +742 -0
  72. package/tools/vds-scripts/confluence_orchestrator/Dockerfile +19 -0
  73. package/tools/vds-scripts/confluence_orchestrator/README.md +412 -0
  74. package/tools/vds-scripts/confluence_orchestrator/SYNC_SCRIPTS.md +127 -0
  75. package/tools/vds-scripts/confluence_orchestrator/SYNC_STANDARDIZATION.md +108 -0
  76. package/tools/vds-scripts/confluence_orchestrator/pyproject.toml +48 -0
  77. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/__init__.py +20 -0
  78. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/cli.py +2532 -0
  79. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/config.py +175 -0
  80. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/content.py +290 -0
  81. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/content_v2.py +94 -0
  82. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/crawl_tree.py +1835 -0
  83. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/errors.py +80 -0
  84. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/eventing.py +109 -0
  85. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/http.py +1114 -0
  86. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/orchestration.py +165 -0
  87. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/reporting.py +78 -0
  88. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/tree.py +121 -0
  89. package/tools/vds-scripts/confluence_orchestrator/sync_pdfs_from_markdown.py +213 -0
  90. package/tools/vds-scripts/confluence_orchestrator/sync_pdfs_to_confluence.py +305 -0
  91. package/tools/vds-scripts/confluence_orchestrator/sync_png_attachments.py +305 -0
  92. package/tools/vds-scripts/confluence_orchestrator/tests/__init__.py +0 -0
  93. package/tools/vds-scripts/confluence_orchestrator/tests/conftest.py +8 -0
  94. package/tools/vds-scripts/confluence_orchestrator/tests/test_advanced_content.py +224 -0
  95. package/tools/vds-scripts/confluence_orchestrator/tests/test_advanced_search.py +188 -0
  96. package/tools/vds-scripts/confluence_orchestrator/tests/test_cache_management.py +247 -0
  97. package/tools/vds-scripts/confluence_orchestrator/tests/test_cli.py +499 -0
  98. package/tools/vds-scripts/confluence_orchestrator/tests/test_config.py +83 -0
  99. package/tools/vds-scripts/confluence_orchestrator/tests/test_content.py +186 -0
  100. package/tools/vds-scripts/confluence_orchestrator/tests/test_content_flags.py +27 -0
  101. package/tools/vds-scripts/confluence_orchestrator/tests/test_crawl_tree.py +2250 -0
  102. package/tools/vds-scripts/confluence_orchestrator/tests/test_draft_management.py +223 -0
  103. package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing.py +71 -0
  104. package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing_chaos.py +37 -0
  105. package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing_rate_limit.py +44 -0
  106. package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing_timeout.py +49 -0
  107. package/tools/vds-scripts/confluence_orchestrator/tests/test_export.py +230 -0
  108. package/tools/vds-scripts/confluence_orchestrator/tests/test_history.py +204 -0
  109. package/tools/vds-scripts/confluence_orchestrator/tests/test_http.py +117 -0
  110. package/tools/vds-scripts/confluence_orchestrator/tests/test_orchestration.py +91 -0
  111. package/tools/vds-scripts/confluence_orchestrator/tests/test_reporting.py +24 -0
  112. package/tools/vds-scripts/confluence_orchestrator/tests/test_search_cql.py +34 -0
  113. package/tools/vds-scripts/confluence_orchestrator/tests/test_space_management.py +237 -0
  114. package/tools/vds-scripts/confluence_orchestrator/tests/test_space_permissions.py +332 -0
  115. package/tools/vds-scripts/confluence_orchestrator/tests/test_user_group_management.py +388 -0
  116. package/tools/vds-scripts/confluence_orchestrator/uv.lock +1023 -0
  117. package/tools/vds-scripts/git_orchestrator/ENHANCEMENT_SUMMARY.md +119 -0
  118. package/tools/vds-scripts/git_orchestrator/README.md +280 -0
  119. package/tools/vds-scripts/git_orchestrator/VERIFICATION_REPORT.md +152 -0
  120. package/tools/vds-scripts/git_orchestrator/pyproject.toml +35 -0
  121. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/__init__.py +7 -0
  122. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/__main__.py +4 -0
  123. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/cli.py +847 -0
  124. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/logging_config.py +63 -0
  125. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/manifest.py +129 -0
  126. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/orchestrator.py +819 -0
  127. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/reporting.py +53 -0
  128. package/tools/vds-scripts/git_orchestrator/tests/__init__.py +0 -0
  129. package/tools/vds-scripts/git_orchestrator/tests/test_cli_settings.py +21 -0
  130. package/tools/vds-scripts/git_orchestrator/tests/test_integration.py +74 -0
  131. package/tools/vds-scripts/git_orchestrator/tests/test_manifest.py +79 -0
  132. package/tools/vds-scripts/git_orchestrator/tests/test_orchestrator.py +204 -0
  133. package/tools/vds-scripts/git_orchestrator/tests/test_public_api.py +236 -0
  134. package/tools/vds-scripts/git_orchestrator/tests/test_resilience.py +345 -0
  135. package/tools/vds-scripts/git_orchestrator/uv.lock +271 -0
  136. package/tools/vds-scripts/jira_orchestrator/README.md +770 -0
  137. package/tools/vds-scripts/jira_orchestrator/pyproject.toml +39 -0
  138. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/__init__.py +1 -0
  139. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/adapter.py +1320 -0
  140. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/cli.py +2271 -0
  141. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/config.py +138 -0
  142. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/errors.py +67 -0
  143. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/reporting.py +65 -0
  144. package/tools/vds-scripts/jira_orchestrator/tests/__init__.py +1 -0
  145. package/tools/vds-scripts/jira_orchestrator/tests/conftest.py +86 -0
  146. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_agile_list_payloads.py +54 -0
  147. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_bulk_operations.py +69 -0
  148. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_components.py +57 -0
  149. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_createmeta.py +45 -0
  150. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_dashboard.py +117 -0
  151. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_issue_properties.py +54 -0
  152. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_permissions_compat.py +42 -0
  153. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_reindex.py +42 -0
  154. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_remote_links.py +76 -0
  155. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_transitions.py +91 -0
  156. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_user_management.py +110 -0
  157. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_version_management.py +133 -0
  158. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_watchers.py +41 -0
  159. package/tools/vds-scripts/jira_orchestrator/tests/test_advanced_search.py +164 -0
  160. package/tools/vds-scripts/jira_orchestrator/tests/test_agile.py +256 -0
  161. package/tools/vds-scripts/jira_orchestrator/tests/test_application_properties.py +193 -0
  162. package/tools/vds-scripts/jira_orchestrator/tests/test_backlog.py +91 -0
  163. package/tools/vds-scripts/jira_orchestrator/tests/test_bulk_operations.py +277 -0
  164. package/tools/vds-scripts/jira_orchestrator/tests/test_cli.py +106 -0
  165. package/tools/vds-scripts/jira_orchestrator/tests/test_components.py +106 -0
  166. package/tools/vds-scripts/jira_orchestrator/tests/test_config.py +164 -0
  167. package/tools/vds-scripts/jira_orchestrator/tests/test_dashboard.py +122 -0
  168. package/tools/vds-scripts/jira_orchestrator/tests/test_discover_fields.py +207 -0
  169. package/tools/vds-scripts/jira_orchestrator/tests/test_filter_management.py +333 -0
  170. package/tools/vds-scripts/jira_orchestrator/tests/test_issue_archiving.py +164 -0
  171. package/tools/vds-scripts/jira_orchestrator/tests/test_issue_links.py +257 -0
  172. package/tools/vds-scripts/jira_orchestrator/tests/test_issue_properties.py +171 -0
  173. package/tools/vds-scripts/jira_orchestrator/tests/test_link_types.py +314 -0
  174. package/tools/vds-scripts/jira_orchestrator/tests/test_parse_set.py +37 -0
  175. package/tools/vds-scripts/jira_orchestrator/tests/test_permissions.py +273 -0
  176. package/tools/vds-scripts/jira_orchestrator/tests/test_reindex.py +81 -0
  177. package/tools/vds-scripts/jira_orchestrator/tests/test_remote_links.py +254 -0
  178. package/tools/vds-scripts/jira_orchestrator/tests/test_security_schemes.py +170 -0
  179. package/tools/vds-scripts/jira_orchestrator/tests/test_transitions_changelog.py +114 -0
  180. package/tools/vds-scripts/jira_orchestrator/tests/test_user_management.py +226 -0
  181. package/tools/vds-scripts/jira_orchestrator/tests/test_version_management.py +339 -0
  182. package/tools/vds-scripts/jira_orchestrator/tests/test_watchers.py +101 -0
  183. package/tools/vds-scripts/jira_orchestrator/tests/test_worklog.py +223 -0
  184. package/tools/vds-scripts/jira_orchestrator/uv.lock +738 -0
  185. package/tools/vds-scripts/mcp_server/Dockerfile +34 -0
  186. package/tools/vds-scripts/mcp_server/README.md +140 -0
  187. package/tools/vds-scripts/mcp_server/pyproject.toml +42 -0
  188. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/__init__.py +4 -0
  189. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/config.py +36 -0
  190. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/server.py +66 -0
  191. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/__init__.py +14 -0
  192. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/bitbucket_tools.py +47 -0
  193. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/confluence_tools.py +59 -0
  194. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/git_tools.py +71 -0
  195. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/jira_tools.py +63 -0
  196. package/tools/vds-scripts/mcp_server/tests/__init__.py +2 -0
  197. package/tools/vds-scripts/mcp_server/tests/conftest.py +29 -0
  198. package/tools/vds-scripts/mcp_server/tests/unit/__init__.py +2 -0
  199. package/tools/vds-scripts/mcp_server/tests/unit/test_bitbucket_tools.py +25 -0
  200. package/tools/vds-scripts/mcp_server/tests/unit/test_confluence_tools.py +25 -0
  201. package/tools/vds-scripts/mcp_server/tests/unit/test_git_tools.py +32 -0
  202. package/tools/vds-scripts/mcp_server/tests/unit/test_jira_tools.py +32 -0
  203. package/tools/vds-scripts/mcp_server/tests/verification/__init__.py +2 -0
  204. package/tools/vds-scripts/mcp_server/tests/verification/test_mcp_confluence_tools.py +40 -0
  205. package/tools/vds-scripts/mcp_server/tests/verification/test_mcp_jira_tools.py +37 -0
  206. package/tools/vds-scripts/mcp_server/tests/verification/test_mcp_tool_registration.py +47 -0
  207. package/tools/vds-scripts/mcp_server/uv.lock +1032 -0
  208. package/tools/vds-scripts/mypy.ini +5 -0
  209. package/tools/vds-scripts/pyproject.toml +29 -0
  210. package/tools/vds-scripts/repo-manifest.yaml +273 -0
  211. package/tools/vds-scripts/repo-manifest.yaml.example +25 -0
  212. package/tools/vds-scripts/scripts/BRD-Validation-API.postman_collection.json +706 -0
  213. package/tools/vds-scripts/scripts/BRD-Validation-README.md +308 -0
  214. package/tools/vds-scripts/scripts/README.md +162 -0
  215. package/tools/vds-scripts/scripts/bootstrap_uv.sh +30 -0
  216. package/tools/vds-scripts/scripts/brd-validation-environment.json +51 -0
  217. package/tools/vds-scripts/scripts/brd-validation-test-results.json +13023 -0
  218. package/tools/vds-scripts/scripts/brd_coverage_report.json +276 -0
  219. package/tools/vds-scripts/scripts/create_memory_session.py +35 -0
  220. package/tools/vds-scripts/scripts/deployment/load_docker_images_offline.sh +90 -0
  221. package/tools/vds-scripts/scripts/final_completion_report.md +139 -0
  222. package/tools/vds-scripts/scripts/folder_structure_report.json +321 -0
  223. package/tools/vds-scripts/scripts/generate_completion_report.py +125 -0
  224. package/tools/vds-scripts/scripts/generate_intellij_modules.py +150 -0
  225. package/tools/vds-scripts/scripts/link_integrity_report.json +807 -0
  226. package/tools/vds-scripts/scripts/move_audit_artifact_pages.py +255 -0
  227. package/tools/vds-scripts/scripts/move_audit_artifact_pages_rest.py +165 -0
  228. package/tools/vds-scripts/scripts/move_wrong_dept_pages.py +216 -0
  229. package/tools/vds-scripts/scripts/save_intellij_memories.py +120 -0
  230. package/tools/vds-scripts/scripts/save_memories_to_vds_ai.py +83 -0
  231. package/tools/vds-scripts/scripts/save_memories_vds_style.py +129 -0
  232. package/tools/vds-scripts/scripts/search_intellij_memories.py +50 -0
  233. package/tools/vds-scripts/scripts/setup_intellij_workspace.py +65 -0
  234. package/tools/vds-scripts/scripts/target-state-automation/README.md +89 -0
  235. package/tools/vds-scripts/scripts/target-state-automation/confluence_sync_coordinator.sh +27 -0
  236. package/tools/vds-scripts/scripts/target-state-automation/coordination.sh +114 -0
  237. package/tools/vds-scripts/scripts/target-state-automation/diagram_coordinator.sh +25 -0
  238. package/tools/vds-scripts/scripts/target-state-automation/docs_root.sh +22 -0
  239. package/tools/vds-scripts/scripts/target-state-automation/generate_diagrams.sh +22 -0
  240. package/tools/vds-scripts/scripts/target-state-automation/markdown_coordinator.sh +25 -0
  241. package/tools/vds-scripts/scripts/target-state-automation/progress_dashboard.sh +17 -0
  242. package/tools/vds-scripts/scripts/target-state-automation/schema_coordinator.sh +25 -0
  243. package/tools/vds-scripts/scripts/target-state-automation/sync_confluence.sh +30 -0
  244. package/tools/vds-scripts/scripts/target-state-automation/update_dependencies.sh +19 -0
  245. package/tools/vds-scripts/scripts/target-state-automation/validate_links.sh +86 -0
  246. package/tools/vds-scripts/scripts/target-state-automation/validate_markdown.sh +52 -0
  247. package/tools/vds-scripts/scripts/target-state-automation/validate_schemas.sh +26 -0
  248. package/tools/vds-scripts/scripts/target-state-automation/validate_structure.sh +98 -0
  249. package/tools/vds-scripts/scripts/update_modules_xml.py +190 -0
  250. package/tools/vds-scripts/scripts/uv-workspace-alignment-verification-2026-03-25.md +128 -0
  251. package/tools/vds-scripts/scripts/validate_brd_coverage.py +179 -0
  252. package/tools/vds-scripts/scripts/validate_folder_structure.py +240 -0
  253. package/tools/vds-scripts/scripts/validate_link_integrity.py +272 -0
  254. package/tools/vds-scripts/scripts/vds_sh_helpers.sh +180 -0
  255. package/tools/vds-scripts/scripts/verification/phase2_portable_paths_ubuntu_docker.sh +26 -0
  256. package/tools/vds-scripts/scripts/worktree_uv.sh +48 -0
  257. package/tools/vds-scripts/uv.lock +8 -0
  258. package/tools/vds-scripts/vds_cli/README.md +126 -0
  259. package/tools/vds-scripts/vds_cli/VERIFICATION_REPORT.md +41 -0
  260. package/tools/vds-scripts/vds_cli/pyproject.toml +38 -0
  261. package/tools/vds-scripts/vds_cli/src/vds_cli/__init__.py +3 -0
  262. package/tools/vds-scripts/vds_cli/src/vds_cli/cli.py +173 -0
  263. package/tools/vds-scripts/vds_cli/src/vds_cli/docs_sync.py +1203 -0
  264. package/tools/vds-scripts/vds_cli/src/vds_cli/env.py +41 -0
  265. package/tools/vds-scripts/vds_cli/src/vds_cli/google_sheets_orchestrator/__init__.py +3 -0
  266. package/tools/vds-scripts/vds_cli/src/vds_cli/google_sheets_orchestrator/google_sheets_orchestrator.py +198 -0
  267. package/tools/vds-scripts/vds_cli/src/vds_cli/router.py +93 -0
  268. package/tools/vds-scripts/vds_cli/src/vds_cli/sync_api.py +647 -0
  269. package/tools/vds-scripts/vds_cli/src/vds_cli/sync_service.py +266 -0
  270. package/tools/vds-scripts/vds_cli/tests/__init__.py +2 -0
  271. package/tools/vds-scripts/vds_cli/tests/conftest.py +49 -0
  272. package/tools/vds-scripts/vds_cli/tests/unit/__init__.py +2 -0
  273. package/tools/vds-scripts/vds_cli/tests/unit/test_cli.py +143 -0
  274. package/tools/vds-scripts/vds_cli/tests/unit/test_docs_sync.py +422 -0
  275. package/tools/vds-scripts/vds_cli/tests/unit/test_env.py +51 -0
  276. package/tools/vds-scripts/vds_cli/tests/unit/test_router.py +72 -0
  277. package/tools/vds-scripts/vds_cli/tests/unit/test_sync_api.py +357 -0
  278. package/tools/vds-scripts/vds_cli/tests/unit/test_sync_service.py +160 -0
  279. package/tools/vds-scripts/vds_cli/tests/verification/__init__.py +2 -0
  280. package/tools/vds-scripts/vds_cli/tests/verification/test_bitbucket_real.py +33 -0
  281. package/tools/vds-scripts/vds_cli/tests/verification/test_confluence_real.py +35 -0
  282. package/tools/vds-scripts/vds_cli/tests/verification/test_jira_real.py +41 -0
  283. package/tools/vds-scripts/vds_cli/uv.lock +524 -0
  284. package/tools/vds-scripts/vds_cli_common/README.md +190 -0
  285. package/tools/vds-scripts/vds_cli_common/pyproject.toml +92 -0
  286. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/__init__.py +34 -0
  287. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/completers.py +139 -0
  288. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/context.py +201 -0
  289. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/env.py +119 -0
  290. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/errors.py +318 -0
  291. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/output.py +284 -0
  292. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/paths.py +78 -0
  293. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/testing.py +213 -0
  294. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/version.py +85 -0
  295. package/tools/vds-scripts/vds_cli_common/tests/__init__.py +1 -0
  296. package/tools/vds-scripts/vds_cli_common/tests/test_completers.py +148 -0
  297. package/tools/vds-scripts/vds_cli_common/tests/test_context.py +192 -0
  298. package/tools/vds-scripts/vds_cli_common/tests/test_env.py +102 -0
  299. package/tools/vds-scripts/vds_cli_common/tests/test_errors.py +186 -0
  300. package/tools/vds-scripts/vds_cli_common/tests/test_output.py +229 -0
  301. package/tools/vds-scripts/vds_cli_common/tests/test_paths.py +61 -0
  302. package/tools/vds-scripts/vds_cli_common/tests/test_testing.py +138 -0
  303. package/tools/vds-scripts/vds_cli_common/tests/test_version.py +64 -0
@@ -0,0 +1,229 @@
1
+ """Tests for OutputManager."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from unittest.mock import MagicMock, patch
7
+
8
+ from vds_cli_common import CLIContext, OutputManager
9
+ from vds_cli_common.output import NullProgress
10
+
11
+
12
+ class TestNullProgress:
13
+ """Tests for NullProgress class."""
14
+
15
+ def test_add_task_returns_zero(self) -> None:
16
+ """Test add_task returns 0."""
17
+ progress = NullProgress()
18
+ task_id = progress.add_task("Test", total=100)
19
+ assert task_id == 0
20
+
21
+ def test_update_is_noop(self) -> None:
22
+ """Test update does nothing."""
23
+ progress = NullProgress()
24
+ # Should not raise
25
+ progress.update(0, advance=1)
26
+
27
+ def test_context_manager(self) -> None:
28
+ """Test NullProgress works as context manager."""
29
+ with NullProgress() as progress:
30
+ assert isinstance(progress, NullProgress)
31
+
32
+
33
+ class TestOutputManager:
34
+ """Tests for OutputManager class."""
35
+
36
+ def test_output_json_compact_in_json_only_mode(self) -> None:
37
+ """Test JSON output is compact in json_only mode."""
38
+ with patch("sys.stdout.isatty", return_value=True):
39
+ ctx = CLIContext.from_options(json_only=True)
40
+ out = OutputManager(ctx)
41
+
42
+ with patch("builtins.print") as mock_print:
43
+ out.output_json({"key": "value"})
44
+ mock_print.assert_called_once()
45
+ call_args = mock_print.call_args[0][0]
46
+ # Should be compact (no indentation)
47
+ assert call_args == '{"key": "value"}'
48
+
49
+ def test_output_json_pretty_in_normal_mode(self) -> None:
50
+ """Test JSON output is pretty-printed in normal mode."""
51
+ with patch("sys.stdout.isatty", return_value=False):
52
+ ctx = CLIContext.from_options(json_only=False)
53
+ out = OutputManager(ctx)
54
+
55
+ with patch("builtins.print") as mock_print:
56
+ out.output_json({"key": "value"}, pretty=True)
57
+ mock_print.assert_called_once()
58
+ call_args = mock_print.call_args[0][0]
59
+ # Should be pretty-printed
60
+ assert " " in call_args or "\n" in call_args
61
+
62
+ def test_output_error_json_format_in_json_only_mode(self) -> None:
63
+ """Test error output is JSON in json_only mode."""
64
+ with patch("sys.stdout.isatty", return_value=True):
65
+ ctx = CLIContext.from_options(json_only=True)
66
+ out = OutputManager(ctx)
67
+
68
+ with patch("builtins.print") as mock_print:
69
+ out.output_error("Test error", hint="Test hint")
70
+ mock_print.assert_called_once()
71
+ call_args = mock_print.call_args[0][0]
72
+ error_obj = json.loads(call_args)
73
+ assert error_obj["error"] is True
74
+ assert error_obj["message"] == "Test error"
75
+ assert error_obj["hint"] == "Test hint"
76
+
77
+ def test_output_error_with_details(self) -> None:
78
+ """Test error output includes details."""
79
+ with patch("sys.stdout.isatty", return_value=True):
80
+ ctx = CLIContext.from_options(json_only=True)
81
+ out = OutputManager(ctx)
82
+
83
+ with patch("builtins.print") as mock_print:
84
+ out.output_error("Error", details={"key": "value"})
85
+ call_args = mock_print.call_args[0][0]
86
+ error_obj = json.loads(call_args)
87
+ assert error_obj["details"] == {"key": "value"}
88
+
89
+ def test_output_success_shown_when_hints_enabled(self) -> None:
90
+ """Test success message is shown when hints enabled."""
91
+ with patch("sys.stdout.isatty", return_value=True):
92
+ ctx = CLIContext.from_options(json_only=False, quiet=False)
93
+ out = OutputManager(ctx)
94
+
95
+ # Mock the console print
96
+ out._console = MagicMock()
97
+ out.output_success("Success!")
98
+ out._console.print.assert_called_once()
99
+
100
+ def test_output_success_hidden_in_quiet_mode(self) -> None:
101
+ """Test success message is hidden in quiet mode."""
102
+ with patch("sys.stdout.isatty", return_value=True):
103
+ ctx = CLIContext.from_options(quiet=True)
104
+ out = OutputManager(ctx)
105
+
106
+ out._console = MagicMock()
107
+ out.output_success("Success!")
108
+ out._console.print.assert_not_called()
109
+
110
+ def test_output_warning_shown_when_hints_enabled(self) -> None:
111
+ """Test warning message is shown when hints enabled."""
112
+ with patch("sys.stdout.isatty", return_value=True):
113
+ ctx = CLIContext.from_options(json_only=False, quiet=False)
114
+ out = OutputManager(ctx)
115
+
116
+ out._console = MagicMock()
117
+ out.output_warning("Warning!")
118
+ out._console.print.assert_called_once()
119
+
120
+ def test_output_info_shown_when_hints_enabled(self) -> None:
121
+ """Test info message is shown when hints enabled."""
122
+ with patch("sys.stdout.isatty", return_value=True):
123
+ ctx = CLIContext.from_options(json_only=False, quiet=False)
124
+ out = OutputManager(ctx)
125
+
126
+ out._console = MagicMock()
127
+ out.output_info("Info!")
128
+ out._console.print.assert_called_once()
129
+
130
+ def test_suggest_next_shown_when_hints_enabled(self) -> None:
131
+ """Test suggestions are shown when hints enabled."""
132
+ with patch("sys.stdout.isatty", return_value=True):
133
+ ctx = CLIContext.from_options(json_only=False, quiet=False)
134
+ out = OutputManager(ctx)
135
+
136
+ out._console = MagicMock()
137
+ out.suggest_next(["search", "count"])
138
+ out._console.print.assert_called_once()
139
+
140
+ def test_suggest_next_hidden_in_json_only_mode(self) -> None:
141
+ """Test suggestions are hidden in json_only mode."""
142
+ ctx = CLIContext.from_options(json_only=True)
143
+ out = OutputManager(ctx)
144
+
145
+ out._console = MagicMock()
146
+ out.suggest_next(["search", "count"])
147
+ out._console.print.assert_not_called()
148
+
149
+ def test_suggest_next_empty_list(self) -> None:
150
+ """Test suggest_next with empty list does nothing."""
151
+ with patch("sys.stdout.isatty", return_value=True):
152
+ ctx = CLIContext.from_options()
153
+ out = OutputManager(ctx)
154
+
155
+ out._console = MagicMock()
156
+ out.suggest_next([])
157
+ out._console.print.assert_not_called()
158
+
159
+ def test_spinner_shown_in_tty(self) -> None:
160
+ """Test spinner is shown in TTY mode."""
161
+ with patch("sys.stdout.isatty", return_value=True):
162
+ ctx = CLIContext.from_options()
163
+ out = OutputManager(ctx)
164
+
165
+ out._err_console = MagicMock()
166
+ out._err_console.status = MagicMock()
167
+
168
+ with out.spinner("Testing..."):
169
+ pass
170
+
171
+ out._err_console.status.assert_called_once()
172
+
173
+ def test_spinner_hidden_in_pipe(self) -> None:
174
+ """Test spinner is hidden when piped."""
175
+ with patch("sys.stdout.isatty", return_value=False):
176
+ ctx = CLIContext.from_options()
177
+ out = OutputManager(ctx)
178
+
179
+ out._err_console = MagicMock()
180
+
181
+ # Should not call status
182
+ with out.spinner("Testing..."):
183
+ pass
184
+
185
+ out._err_console.status.assert_not_called()
186
+
187
+ def test_progress_returns_null_in_pipe(self) -> None:
188
+ """Test progress returns NullProgress when piped."""
189
+ with patch("sys.stdout.isatty", return_value=False):
190
+ ctx = CLIContext.from_options()
191
+ out = OutputManager(ctx)
192
+
193
+ with out.progress("Test", total=100) as progress:
194
+ assert isinstance(progress, NullProgress)
195
+
196
+ def test_table_returns_none_in_json_only_mode(self) -> None:
197
+ """Test table returns None in json_only mode."""
198
+ ctx = CLIContext.from_options(json_only=True)
199
+ out = OutputManager(ctx)
200
+
201
+ table = out.table("Test", columns=["A", "B"])
202
+ assert table is None
203
+
204
+ def test_table_returns_table_in_tty(self) -> None:
205
+ """Test table returns Rich Table in TTY mode."""
206
+ with patch("sys.stdout.isatty", return_value=True):
207
+ ctx = CLIContext.from_options()
208
+ out = OutputManager(ctx)
209
+
210
+ table = out.table("Test", columns=["A", "B"], rows=[["1", "2"]])
211
+ assert table is not None
212
+
213
+ def test_print_delegates_to_console(self) -> None:
214
+ """Test print delegates to console."""
215
+ ctx = CLIContext()
216
+ out = OutputManager(ctx)
217
+
218
+ out._console = MagicMock()
219
+ out.print("Hello")
220
+ out._console.print.assert_called_once_with("Hello")
221
+
222
+ def test_print_err_delegates_to_err_console(self) -> None:
223
+ """Test print_err delegates to err_console."""
224
+ ctx = CLIContext()
225
+ out = OutputManager(ctx)
226
+
227
+ out._err_console = MagicMock()
228
+ out.print_err("Error")
229
+ out._err_console.print.assert_called_once_with("Error")
@@ -0,0 +1,61 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from vds_cli_common import paths
6
+
7
+
8
+ def test_get_vds_config_root_prefers_env_override(monkeypatch, tmp_path: Path) -> None:
9
+ override = tmp_path / "custom-config"
10
+ monkeypatch.setenv("VDS_CONFIG_DIR", str(override))
11
+
12
+ assert paths.get_vds_config_root() == override.resolve()
13
+
14
+
15
+ def test_get_default_env_paths_only_include_shared_env_path(monkeypatch, tmp_path: Path) -> None:
16
+ config_root = tmp_path / ".vds"
17
+
18
+ monkeypatch.delenv("VDS_ENV_FILE", raising=False)
19
+ monkeypatch.delenv("VDS_CONFIG_DIR", raising=False)
20
+ monkeypatch.setattr(paths, "_default_vds_home", lambda: config_root)
21
+
22
+ env_paths = paths.get_default_env_paths()
23
+
24
+ assert len(env_paths) == 1
25
+ assert env_paths[0] == config_root / ".env"
26
+
27
+
28
+ def test_get_vds_data_root_uses_vds_home_default(monkeypatch, tmp_path: Path) -> None:
29
+ config_root = tmp_path / ".vds"
30
+
31
+ monkeypatch.delenv("VDS_DATA_DIR", raising=False)
32
+ monkeypatch.delenv("VDS_CONFIG_DIR", raising=False)
33
+ monkeypatch.setattr(paths, "_default_vds_home", lambda: config_root)
34
+
35
+ assert paths.get_vds_data_root() == config_root / "data"
36
+
37
+
38
+ def test_get_vds_log_root_uses_vds_home_logs_default(monkeypatch, tmp_path: Path) -> None:
39
+ config_root = tmp_path / ".vds"
40
+
41
+ monkeypatch.delenv("VDS_LOG_DIR", raising=False)
42
+ monkeypatch.delenv("VDS_CONFIG_DIR", raising=False)
43
+ monkeypatch.setattr(paths, "_default_vds_home", lambda: config_root)
44
+
45
+ assert paths.get_vds_log_root() == config_root / "logs"
46
+
47
+
48
+ def test_get_vds_config_root_uses_vds_home_default_when_no_override(monkeypatch, tmp_path: Path) -> None:
49
+ config_root = tmp_path / ".vds"
50
+
51
+ monkeypatch.delenv("VDS_CONFIG_DIR", raising=False)
52
+ monkeypatch.setattr(paths, "_default_vds_home", lambda: config_root)
53
+
54
+ assert paths.get_vds_config_root() == config_root
55
+
56
+
57
+ def test_get_shared_env_path_prefers_env_file_override(monkeypatch, tmp_path: Path) -> None:
58
+ override = tmp_path / "config" / "custom.env"
59
+ monkeypatch.setenv("VDS_ENV_FILE", str(override))
60
+
61
+ assert paths.get_shared_env_path() == override.resolve()
@@ -0,0 +1,138 @@
1
+ """Tests for testing utilities."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import sys
7
+
8
+ from vds_cli_common import CLIContext
9
+ from vds_cli_common.testing import (
10
+ capture_output,
11
+ create_test_context,
12
+ create_test_output,
13
+ mock_force_color_env,
14
+ mock_no_color_env,
15
+ mock_pipe,
16
+ mock_tty,
17
+ )
18
+
19
+
20
+ class TestMockTty:
21
+ """Tests for mock_tty context manager."""
22
+
23
+ def test_mocks_isatty_true(self) -> None:
24
+ """Test mock_tty makes isatty return True."""
25
+ with mock_tty():
26
+ assert sys.stdout.isatty() is True
27
+
28
+ def test_restores_after_context(self) -> None:
29
+ """Test mock_tty restores original after context."""
30
+ original = sys.stdout.isatty()
31
+ with mock_tty():
32
+ pass
33
+ # Should be restored (may still be True if actually TTY)
34
+ assert sys.stdout.isatty() == original
35
+
36
+
37
+ class TestMockPipe:
38
+ """Tests for mock_pipe context manager."""
39
+
40
+ def test_mocks_isatty_false(self) -> None:
41
+ """Test mock_pipe makes isatty return False."""
42
+ with mock_pipe():
43
+ assert sys.stdout.isatty() is False
44
+
45
+
46
+ class TestMockNoColorEnv:
47
+ """Tests for mock_no_color_env context manager."""
48
+
49
+ def test_sets_no_color_env(self) -> None:
50
+ """Test mock_no_color_env sets NO_COLOR."""
51
+ with mock_no_color_env():
52
+ assert os.environ.get("NO_COLOR") == "1"
53
+
54
+ def test_restores_after_context(self) -> None:
55
+ """Test mock_no_color_env restores env after context."""
56
+ original = os.environ.get("NO_COLOR")
57
+ with mock_no_color_env():
58
+ pass
59
+ assert os.environ.get("NO_COLOR") == original
60
+
61
+
62
+ class TestMockForceColorEnv:
63
+ """Tests for mock_force_color_env context manager."""
64
+
65
+ def test_sets_force_color_env(self) -> None:
66
+ """Test mock_force_color_env sets FORCE_COLOR."""
67
+ with mock_force_color_env():
68
+ assert os.environ.get("FORCE_COLOR") == "1"
69
+
70
+
71
+ class TestCaptureOutput:
72
+ """Tests for capture_output context manager."""
73
+
74
+ def test_captures_stdout(self) -> None:
75
+ """Test capture_output captures stdout."""
76
+ with capture_output() as captured:
77
+ print("Hello")
78
+ assert any("Hello" in s for s in captured["stdout"])
79
+
80
+ def test_captures_stderr(self) -> None:
81
+ """Test capture_output captures stderr."""
82
+ with capture_output() as captured:
83
+ print("Error", file=sys.stderr)
84
+ assert any("Error" in s for s in captured["stderr"])
85
+
86
+ def test_empty_by_default(self) -> None:
87
+ """Test captured is empty by default."""
88
+ with capture_output() as captured:
89
+ pass
90
+ assert captured["stdout"] == []
91
+ assert captured["stderr"] == []
92
+
93
+
94
+ class TestCreateTestContext:
95
+ """Tests for create_test_context helper."""
96
+
97
+ def test_creates_context_with_defaults(self) -> None:
98
+ """Test creates context with default settings."""
99
+ ctx = create_test_context()
100
+ assert isinstance(ctx, CLIContext)
101
+ assert ctx.json_only is False
102
+ assert ctx.quiet is False
103
+
104
+ def test_creates_context_with_json_only(self) -> None:
105
+ """Test creates context with json_only."""
106
+ ctx = create_test_context(json_only=True)
107
+ assert ctx.json_only is True
108
+
109
+ def test_creates_context_with_quiet(self) -> None:
110
+ """Test creates context with quiet mode."""
111
+ ctx = create_test_context(quiet=True)
112
+ assert ctx.quiet is True
113
+
114
+ def test_creates_context_with_tty_mock(self) -> None:
115
+ """Test creates context with TTY mocked."""
116
+ ctx = create_test_context(is_tty=True)
117
+ assert ctx.is_tty is True
118
+
119
+ ctx = create_test_context(is_tty=False)
120
+ assert ctx.is_tty is False
121
+
122
+
123
+ class TestCreateTestOutput:
124
+ """Tests for create_test_output helper."""
125
+
126
+ def test_creates_output_manager(self) -> None:
127
+ """Test creates OutputManager."""
128
+ from vds_cli_common import OutputManager
129
+
130
+ output = create_test_output()
131
+ assert isinstance(output, OutputManager)
132
+
133
+ def test_uses_provided_context(self) -> None:
134
+ """Test uses provided CLIContext."""
135
+ ctx = create_test_context(json_only=True)
136
+ output = create_test_output(ctx)
137
+ assert output.ctx is ctx
138
+ assert output.ctx.json_only is True
@@ -0,0 +1,64 @@
1
+ """Tests for version callback factory."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from unittest.mock import patch
6
+
7
+ import pytest
8
+ import typer
9
+
10
+ from vds_cli_common.version import create_version_callback, get_package_version
11
+
12
+
13
+ class TestCreateVersionCallback:
14
+ """Tests for create_version_callback function."""
15
+
16
+ def test_callback_prints_version_and_exits(self) -> None:
17
+ """Test callback prints version and exits when value is True."""
18
+ callback = create_version_callback("vds-cli-common")
19
+
20
+ with patch("typer.echo") as mock_echo:
21
+ with pytest.raises(typer.Exit) as exc_info:
22
+ callback(True)
23
+
24
+ assert exc_info.value.exit_code == 0
25
+ mock_echo.assert_called_once()
26
+ call_args = mock_echo.call_args[0][0]
27
+ assert "vds-cli-common" in call_args
28
+
29
+ def test_callback_does_nothing_when_false(self) -> None:
30
+ """Test callback does nothing when value is False."""
31
+ callback = create_version_callback("vds-cli-common")
32
+
33
+ with patch("typer.echo") as mock_echo:
34
+ # Should not raise or print
35
+ result = callback(False)
36
+ assert result is None
37
+ mock_echo.assert_not_called()
38
+
39
+ def test_callback_handles_unknown_package(self) -> None:
40
+ """Test callback handles unknown package gracefully."""
41
+ callback = create_version_callback("nonexistent-package-xyz")
42
+
43
+ with patch("typer.echo") as mock_echo:
44
+ with pytest.raises(typer.Exit):
45
+ callback(True)
46
+
47
+ call_args = mock_echo.call_args[0][0]
48
+ assert "unknown" in call_args
49
+
50
+
51
+ class TestGetPackageVersion:
52
+ """Tests for get_package_version function."""
53
+
54
+ def test_returns_version_for_known_package(self) -> None:
55
+ """Test returns version for installed package."""
56
+ # typer should be installed
57
+ version = get_package_version("typer")
58
+ assert version != "unknown"
59
+ assert "." in version # Should have version format
60
+
61
+ def test_returns_unknown_for_missing_package(self) -> None:
62
+ """Test returns 'unknown' for missing package."""
63
+ version = get_package_version("nonexistent-package-xyz")
64
+ assert version == "unknown"