@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,255 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Move audit artifact pages under an 'Audit History' child page.
4
+
5
+ Target: Department page 88716694 (Payment department)
6
+ Pages to move:
7
+ - "Project Analysis - 88718879"
8
+ - "Project Analysis - 88718884"
9
+ - "Project Analysis - 88718886"
10
+ - "Project Analysis - 88718943"
11
+ - "Project Analysis - 88718977"
12
+ - "Project Audit - 88718879"
13
+ - "Project Audit - 88718884"
14
+ - "Project Audit - 88718886"
15
+ - "Project Audit - 88718943"
16
+ - "Project Audit - 88718977"
17
+
18
+ Usage:
19
+ uv run --project audit_orchestrator python3 scripts/move_audit_artifact_pages.py
20
+
21
+ Prerequisites:
22
+ - ~/.vds/.env must be populated with VDS_USERNAME, VDS_PASSWORD
23
+ - CONFLUENCE_INTERNAL_URL must be accessible (requires VPN/internal network)
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import asyncio
29
+ import json
30
+ import sys
31
+ from pathlib import Path
32
+
33
+ # ---------------------------------------------------------------------------
34
+ # Bootstrap environment
35
+ # ---------------------------------------------------------------------------
36
+ env_path = Path("/Users/vds-ai/.vds/.env")
37
+ if env_path.exists():
38
+ from dotenv import load_dotenv
39
+ load_dotenv(env_path)
40
+
41
+ from vds_audit_orchestrator.clients.confluence_cli_client import ConfluenceCliClient
42
+
43
+ # ---------------------------------------------------------------------------
44
+ # Configuration
45
+ # ---------------------------------------------------------------------------
46
+ DEPARTMENT_PAGE_ID = "88716694"
47
+ AUDIT_HISTORY_TITLE = "Audit History"
48
+
49
+ # Pages to move: (title, page_id_in_title) - the IDs embedded in the titles
50
+ ARTIFACT_PAGE_IDS = [
51
+ "88718879",
52
+ "88718884",
53
+ "88718886",
54
+ "88718943",
55
+ "88718977",
56
+ ]
57
+
58
+ ARTIFACT_PAGE_TITLES = (
59
+ [f"Project Analysis - {pid}" for pid in ARTIFACT_PAGE_IDS]
60
+ + [f"Project Audit - {pid}" for pid in ARTIFACT_PAGE_IDS]
61
+ )
62
+
63
+
64
+ async def connectivity_check(client: ConfluenceCliClient) -> bool:
65
+ """Verify Confluence is reachable by fetching the department page."""
66
+ try:
67
+ page = await asyncio.wait_for(
68
+ client.get_page(DEPARTMENT_PAGE_ID, expand="version,space"),
69
+ timeout=15,
70
+ )
71
+ if page and page.get("title"):
72
+ print(f"[OK] Connected to Confluence. Department page: {page['title']!r}")
73
+ return True
74
+ print(f"[WARN] Page {DEPARTMENT_PAGE_ID} not found or no permission.")
75
+ return False
76
+ except asyncio.TimeoutError:
77
+ print("[ERROR] Confluence connection timed out. Check VPN/network access.")
78
+ return False
79
+ except Exception as exc:
80
+ print(f"[ERROR] Confluence connectivity check failed: {exc}")
81
+ return False
82
+
83
+
84
+ async def find_or_create_audit_history_page(
85
+ client: ConfluenceCliClient,
86
+ space_key: str,
87
+ ) -> str:
88
+ """Return the page ID of 'Audit History' under the department page, creating it if absent."""
89
+ children = await client.get_child_pages(DEPARTMENT_PAGE_ID)
90
+ for child in children:
91
+ if child.get("title") == AUDIT_HISTORY_TITLE:
92
+ page_id = child["id"]
93
+ print(f"[OK] Found existing 'Audit History' page: {page_id}")
94
+ return page_id
95
+
96
+ print(f"[INFO] 'Audit History' page not found under {DEPARTMENT_PAGE_ID}. Creating...")
97
+ body_file = Path("/tmp/audit_history_body.html")
98
+ body_file.write_text(
99
+ "<p>This page archives historical audit artifacts for the Payment department.</p>",
100
+ encoding="utf-8",
101
+ )
102
+ result = await client.create_page(
103
+ space_key=space_key,
104
+ title=AUDIT_HISTORY_TITLE,
105
+ body_file=body_file,
106
+ parent_id=DEPARTMENT_PAGE_ID,
107
+ )
108
+ new_id = result.get("id") or result.get("page_id")
109
+ if not new_id:
110
+ raise RuntimeError(f"Failed to create 'Audit History' page. Response: {result}")
111
+ print(f"[OK] Created 'Audit History' page: {new_id}")
112
+ return str(new_id)
113
+
114
+
115
+ async def get_pages_to_move(client: ConfluenceCliClient) -> list[dict]:
116
+ """Get the current children of the department page that match the artifact pattern."""
117
+ children = await client.get_child_pages(DEPARTMENT_PAGE_ID)
118
+ pages_to_move = []
119
+ for child in children:
120
+ title = child.get("title", "")
121
+ if title in ARTIFACT_PAGE_TITLES:
122
+ pages_to_move.append(child)
123
+ print(f" Found artifact page: {title!r} (id={child['id']})")
124
+ return pages_to_move
125
+
126
+
127
+ async def move_pages(
128
+ client: ConfluenceCliClient,
129
+ pages: list[dict],
130
+ audit_history_page_id: str,
131
+ space_key: str,
132
+ ) -> dict[str, list[str]]:
133
+ """Move all artifact pages under the Audit History page."""
134
+ results: dict[str, list[str]] = {"moved": [], "failed": []}
135
+
136
+ for page in pages:
137
+ page_id = page["id"]
138
+ title = page.get("title", page_id)
139
+ try:
140
+ # Use PUT to update ancestors (move page)
141
+ # The move_page method uses content.move_page which moves by title
142
+ # We need to reparent using update_page's ancestor field
143
+ # Use the REST API approach: update with new ancestors
144
+ await reparent_page(client, page_id, audit_history_page_id, title)
145
+ print(f" [OK] Moved: {title!r} -> Audit History")
146
+ results["moved"].append(title)
147
+ except Exception as exc:
148
+ print(f" [FAIL] Could not move {title!r}: {exc}")
149
+ results["failed"].append(f"{title}: {exc}")
150
+
151
+ return results
152
+
153
+
154
+ async def reparent_page(
155
+ client: ConfluenceCliClient,
156
+ page_id: str,
157
+ new_parent_id: str,
158
+ title: str,
159
+ ) -> None:
160
+ """Move a page to a new parent by calling atlassian update_page with parent_id."""
161
+ # Get current page body (required to not wipe content on update)
162
+ page = await client.get_page(page_id, expand="version,body.storage,space")
163
+ if not page:
164
+ raise ValueError(f"Page {page_id} not found")
165
+
166
+ body_content = page.get("body", {}).get("storage", {}).get("value", "")
167
+
168
+ # Use the atlassian-python-api client directly — it supports parent_id
169
+ # client._http._client is the atlassian.Confluence instance
170
+ result = await asyncio.to_thread(
171
+ client._http._client.update_page,
172
+ page_id,
173
+ title,
174
+ body_content,
175
+ parent_id=new_parent_id,
176
+ representation="storage",
177
+ always_update=True,
178
+ version_comment="Moved to Audit History archive",
179
+ )
180
+ if not result:
181
+ raise RuntimeError(f"update_page returned falsy result for page {page_id}")
182
+
183
+
184
+ async def main() -> int:
185
+ print("=" * 60)
186
+ print("Audit Artifact Page Migration")
187
+ print(f"Department page: {DEPARTMENT_PAGE_ID}")
188
+ print(f"Target: '{AUDIT_HISTORY_TITLE}' child page")
189
+ print("=" * 60)
190
+
191
+ client = ConfluenceCliClient(timeout=30)
192
+
193
+ # Step 1: Connectivity check
194
+ print("\n[1/4] Checking Confluence connectivity...")
195
+ if not await connectivity_check(client):
196
+ print("\nABORTED: Cannot reach Confluence. Ensure you have VPN/network access.")
197
+ return 1
198
+
199
+ # Step 2: Get space key for creating the Audit History page
200
+ dept_page = await client.get_page(DEPARTMENT_PAGE_ID, expand="space")
201
+ space_key = dept_page.get("space", {}).get("key", "") if dept_page else ""
202
+ if not space_key:
203
+ print("[ERROR] Could not determine space key from department page.")
204
+ return 1
205
+ print(f"[OK] Space key: {space_key}")
206
+
207
+ # Step 3: Find pages to move
208
+ print("\n[2/4] Scanning children of department page for artifact pages...")
209
+ pages_to_move = await get_pages_to_move(client)
210
+ if not pages_to_move:
211
+ print("[INFO] No artifact pages found. Already moved or not present.")
212
+ return 0
213
+ print(f"Found {len(pages_to_move)} pages to move.")
214
+
215
+ # Step 4: Ensure Audit History page exists
216
+ print("\n[3/4] Ensuring 'Audit History' page exists...")
217
+ audit_history_id = await find_or_create_audit_history_page(client, space_key)
218
+
219
+ # Step 5: Move pages
220
+ print(f"\n[4/4] Moving {len(pages_to_move)} pages to Audit History ({audit_history_id})...")
221
+ results = await move_pages(client, pages_to_move, audit_history_id, space_key)
222
+
223
+ # Summary
224
+ print("\n" + "=" * 60)
225
+ print("MIGRATION SUMMARY")
226
+ print(f" Moved: {len(results['moved'])}")
227
+ print(f" Failed: {len(results['failed'])}")
228
+ if results["moved"]:
229
+ print("\nSuccessfully moved:")
230
+ for t in results["moved"]:
231
+ print(f" - {t}")
232
+ if results["failed"]:
233
+ print("\nFailed:")
234
+ for t in results["failed"]:
235
+ print(f" - {t}")
236
+ print("=" * 60)
237
+
238
+ # Verify final state
239
+ print("\n[Verify] Remaining children of department page...")
240
+ remaining = await client.get_child_pages(DEPARTMENT_PAGE_ID)
241
+ artifact_remaining = [
242
+ c for c in remaining if c.get("title", "") in ARTIFACT_PAGE_TITLES
243
+ ]
244
+ if artifact_remaining:
245
+ print(f"[WARN] {len(artifact_remaining)} artifact pages still under department page:")
246
+ for c in artifact_remaining:
247
+ print(f" - {c.get('title')} (id={c['id']})")
248
+ else:
249
+ print("[OK] No artifact pages remain directly under the department page.")
250
+
251
+ return 0 if not results["failed"] else 1
252
+
253
+
254
+ if __name__ == "__main__":
255
+ sys.exit(asyncio.run(main()))
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Move audit artifact pages under an 'Audit History' child page.
4
+ Uses ConfluenceCliClient (vds-scripts SDK) — no raw HTTP calls.
5
+
6
+ Usage:
7
+ uv run --project audit_orchestrator python3 scripts/move_audit_artifact_pages_rest.py
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import asyncio
13
+ import sys
14
+ import tempfile
15
+ from pathlib import Path
16
+
17
+ # ---------------------------------------------------------------------------
18
+ # Configuration
19
+ # ---------------------------------------------------------------------------
20
+ DEPARTMENT_PAGE_ID = "88716694"
21
+ AUDIT_HISTORY_TITLE = "Audit History"
22
+
23
+ ARTIFACT_PAGE_IDS = ["88718879", "88718884", "88718886", "88718943", "88718977"]
24
+ ARTIFACT_PAGE_TITLES = set(
25
+ [f"Project Analysis - {pid}" for pid in ARTIFACT_PAGE_IDS] + [f"Project Audit - {pid}" for pid in ARTIFACT_PAGE_IDS]
26
+ )
27
+
28
+
29
+ async def main() -> int:
30
+ from vds_audit_orchestrator.clients.confluence_cli_client import ConfluenceCliClient
31
+
32
+ print("=" * 60)
33
+ print("Audit Artifact Page Migration (ConfluenceCliClient SDK)")
34
+ print(f" Department page: {DEPARTMENT_PAGE_ID}")
35
+ print(f" Target container: '{AUDIT_HISTORY_TITLE}'")
36
+ print("=" * 60)
37
+
38
+ client = ConfluenceCliClient()
39
+
40
+ # 1. Connectivity check
41
+ print("\n[1/4] Checking Confluence connectivity...")
42
+ reachable, detail = await client.probe_reachable()
43
+ if not reachable:
44
+ print(f" [FAIL] Confluence not reachable: {detail}")
45
+ print(" Check VPN/credentials in ~/.vds/.env")
46
+ return 1
47
+
48
+ dept_page = await client.get_page(DEPARTMENT_PAGE_ID, expand="version,space")
49
+ if not dept_page or not dept_page.get("title"):
50
+ print(f" [FAIL] Could not fetch department page {DEPARTMENT_PAGE_ID}.")
51
+ return 1
52
+
53
+ space_key = dept_page.get("space", {}).get("key", "")
54
+ if not space_key:
55
+ print("[ERROR] Cannot determine space key.")
56
+ return 1
57
+ print(f" [OK] Department page: {dept_page['title']!r} (space: {space_key})")
58
+
59
+ # 2. List current children
60
+ print("\n[2/4] Listing children of department page...")
61
+ children = await client.list_child_pages(DEPARTMENT_PAGE_ID)
62
+ print(f" Total children found: {len(children)}")
63
+
64
+ pages_to_move = [c for c in children if c.get("title", "") in ARTIFACT_PAGE_TITLES]
65
+ audit_history_existing = [c for c in children if c.get("title", "") == AUDIT_HISTORY_TITLE]
66
+
67
+ print(f" Artifact pages to move: {len(pages_to_move)}")
68
+ for p in pages_to_move:
69
+ print(f" - {p.get('title')!r} (id={p['id']})")
70
+
71
+ if not pages_to_move:
72
+ print(" [INFO] No artifact pages found. Already moved or not present.")
73
+ return 0
74
+
75
+ # 3. Get or create Audit History page
76
+ print("\n[3/4] Getting/creating 'Audit History' page...")
77
+ if audit_history_existing:
78
+ audit_history_id = audit_history_existing[0]["id"]
79
+ print(f" [OK] Found existing: id={audit_history_id}")
80
+ else:
81
+ print(" Creating 'Audit History' page...")
82
+ body_html = (
83
+ "<p>This page archives historical audit artifact pages "
84
+ "for the <strong>3.2.4 Nền tảng thanh toán</strong> department.</p>"
85
+ )
86
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False, encoding="utf-8") as tmp:
87
+ tmp.write(body_html)
88
+ tmp_path = Path(tmp.name)
89
+
90
+ try:
91
+ new_page = await client.create_page(
92
+ space_key=space_key,
93
+ title=AUDIT_HISTORY_TITLE,
94
+ body_file=tmp_path,
95
+ parent_id=DEPARTMENT_PAGE_ID,
96
+ )
97
+ finally:
98
+ tmp_path.unlink(missing_ok=True)
99
+
100
+ if not new_page or not new_page.get("id"):
101
+ print(f" [ERROR] Failed to create 'Audit History' page. Response: {new_page}")
102
+ return 1
103
+ audit_history_id = str(new_page["id"])
104
+ print(f" [OK] Created: id={audit_history_id}")
105
+
106
+ # 4. Move pages using move_page (by target title)
107
+ print(f"\n[4/4] Moving {len(pages_to_move)} pages to '{AUDIT_HISTORY_TITLE}' ({audit_history_id})...")
108
+ moved: list[str] = []
109
+ failed: list[str] = []
110
+
111
+ for page_meta in pages_to_move:
112
+ page_id = page_meta["id"]
113
+ title = page_meta.get("title", page_id)
114
+
115
+ result = await client.move_page(
116
+ page_id,
117
+ AUDIT_HISTORY_TITLE,
118
+ position="append",
119
+ )
120
+
121
+ if result or result == {}:
122
+ # move_page returns {} on success (no body) or a dict
123
+ print(f" [OK] Moved: {title!r}")
124
+ moved.append(title)
125
+ else:
126
+ print(f" [FAIL] Could not move: {title!r}")
127
+ failed.append(f"{title}: move_page returned no result")
128
+
129
+ # Summary
130
+ print("\n" + "=" * 60)
131
+ print("MIGRATION SUMMARY")
132
+ print(f" Moved: {len(moved)}")
133
+ print(f" Failed: {len(failed)}")
134
+ if moved:
135
+ print("\nSuccessfully moved:")
136
+ for t in moved:
137
+ print(f" - {t}")
138
+ if failed:
139
+ print("\nFailed:")
140
+ for t in failed:
141
+ print(f" - {t}")
142
+ print("=" * 60)
143
+
144
+ # Verify
145
+ print("\n[Verify] Remaining artifact pages under department page...")
146
+ remaining_children = await client.list_child_pages(DEPARTMENT_PAGE_ID)
147
+ still_there = [c for c in remaining_children if c.get("title", "") in ARTIFACT_PAGE_TITLES]
148
+ if still_there:
149
+ print(f"[WARN] {len(still_there)} artifact pages still directly under department:")
150
+ for c in still_there:
151
+ print(f" - {c.get('title')} (id={c['id']})")
152
+ else:
153
+ print("[OK] No artifact pages remain directly under the department page.")
154
+
155
+ print(f"\n[Verify] Children of 'Audit History' page ({audit_history_id})...")
156
+ ah_children = await client.list_child_pages(audit_history_id)
157
+ print(f" {len(ah_children)} pages now under 'Audit History':")
158
+ for c in ah_children:
159
+ print(f" - {c.get('title')} (id={c['id']})")
160
+
161
+ return 0 if not failed else 1
162
+
163
+
164
+ if __name__ == "__main__":
165
+ sys.exit(asyncio.run(main()))
@@ -0,0 +1,216 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Move 14 wrong-department pages from Payment dept (88716694) to their correct
4
+ department parent pages. Also renames pages with '- 88716694' suffix and
5
+ archives a duplicate.
6
+
7
+ Usage:
8
+ uv run --project audit_orchestrator python3 scripts/move_wrong_dept_pages.py
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import asyncio
14
+ import sys
15
+
16
+ # ---------------------------------------------------------------------------
17
+ # Move plan: (page_id, target_parent_id)
18
+ # ---------------------------------------------------------------------------
19
+ PAGES_TO_MOVE = [
20
+ # Admin Products (88716677)
21
+ ("93487312", "88716677"), # Project Analysis - 88718856
22
+ ("93487308", "88716677"), # Project Audit - 88718856
23
+ ("93487326", "88716677"), # Project Analysis - 88718889
24
+ ("93487285", "88716677"), # Project Audit - 88718884 - 88716694
25
+ ("93487290", "88716677"), # Project Audit - 88718886 - 88716694
26
+ ("93487294", "88716677"), # Project Audit - 88718879 - 88716694
27
+ ("93487299", "88716677"), # Project Audit - 88718877 - 88716694
28
+ # App Platform (88716679)
29
+ ("93487303", "88716679"), # Project Audit - 88718882 - 88716694
30
+ # Finance (88716692)
31
+ ("93487316", "88716692"), # Project Analysis - 88718866
32
+ ("93487321", "88716692"), # Project Analysis - 88718868
33
+ ("93487314", "88716692"), # Project Audit - 88718866
34
+ ("93487319", "88716692"), # Project Audit - 88718868
35
+ # Core Tech (88718815)
36
+ ("93487328", "88718815"), # Project Analysis - 88718983
37
+ ("93127125", "88718815"), # Project Audit - 88718940 - 88716694
38
+ ]
39
+
40
+ # ---------------------------------------------------------------------------
41
+ # Rename plan: (page_id, new_title)
42
+ # ---------------------------------------------------------------------------
43
+ PAGES_TO_RENAME = [
44
+ ("93126787", "Project Audit - 88718943"),
45
+ ("93127090", "Project Audit - 88718975"),
46
+ ("93126805", "Project Audit - 88718977"),
47
+ ("93126810", "Project Audit - 88719105"),
48
+ ("93487279", "Project Audit - 91335346"),
49
+ ]
50
+
51
+ # ---------------------------------------------------------------------------
52
+ # Archive duplicate: (page_id, new_title, target_parent_id)
53
+ # ---------------------------------------------------------------------------
54
+ ARCHIVE_PAGE = ("93487283", "[ARCHIVED] Project Analysis - 91335346 (duplicate)", "88727274")
55
+
56
+ SLEEP_BETWEEN_OPS = 5 # seconds
57
+
58
+
59
+ async def main() -> int:
60
+ from vds_audit_orchestrator.clients.confluence_cli_client import ConfluenceCliClient
61
+
62
+ print("=" * 70)
63
+ print("Wrong-Department Page Migration & Cleanup")
64
+ print("=" * 70)
65
+
66
+ client = ConfluenceCliClient()
67
+
68
+ # 1. Connectivity check — use get_page on a known page instead of probe_reachable
69
+ # (probe_reachable calls get_all_groups which times out on this server)
70
+ print("\n[Step 1] Checking Confluence connectivity via get_page(88716694)...")
71
+ test_page = await client.get_page("88716694", expand="version,space")
72
+ if not test_page or not test_page.get("title"):
73
+ print(" [FAIL] Could not fetch Payment dept page 88716694.")
74
+ print(" Check VPN/LAN and credentials in ~/.vds/.env")
75
+ return 1
76
+ space_key = test_page.get("space", {}).get("key", "")
77
+ print(f" [OK] Reachable — page: {test_page['title']!r} (space: {space_key})")
78
+
79
+ # 2. Resolve target parent titles (needed by move_page which takes a title)
80
+ print("\n[Step 2] Resolving target parent page titles...")
81
+ unique_parent_ids = list({parent_id for _, parent_id in PAGES_TO_MOVE} | {ARCHIVE_PAGE[2]})
82
+ parent_titles: dict[str, str] = {}
83
+
84
+ for pid in unique_parent_ids:
85
+ page = await client.get_page(pid, expand="version")
86
+ if page and page.get("title"):
87
+ parent_titles[pid] = page["title"]
88
+ print(f" [OK] {pid} -> {page['title']!r}")
89
+ else:
90
+ print(f" [FAIL] Could not fetch parent page {pid}")
91
+ return 1
92
+
93
+ # 3. Move pages
94
+ print(f"\n[Step 3] Moving {len(PAGES_TO_MOVE)} pages to correct departments...")
95
+ move_success = 0
96
+ move_fail = 0
97
+
98
+ for page_id, target_parent_id in PAGES_TO_MOVE:
99
+ target_title = parent_titles[target_parent_id]
100
+
101
+ # Get current page info for logging
102
+ page_info = await client.get_page(page_id, expand="version")
103
+ current_title = page_info.get("title", page_id) if page_info else page_id
104
+
105
+ print(f"\n Moving: {current_title!r}")
106
+ print(f" page_id={page_id} -> parent={target_parent_id} ({target_title!r})")
107
+
108
+ try:
109
+ result = await client.move_page(page_id, target_title, position="append")
110
+ # move_page returns {} on success (empty body from Confluence REST)
111
+ print(f" [OK] Moved successfully (result={result!r})")
112
+ move_success += 1
113
+ except Exception as exc:
114
+ print(f" [FAIL] Exception: {exc}")
115
+ # Retry once after 30s
116
+ print(" Waiting 30s and retrying once...")
117
+ await asyncio.sleep(30)
118
+ try:
119
+ result = await client.move_page(page_id, target_title, position="append")
120
+ print(f" [OK] Moved on retry (result={result!r})")
121
+ move_success += 1
122
+ except Exception as exc2:
123
+ print(f" [FAIL] Retry also failed: {exc2}")
124
+ move_fail += 1
125
+ continue
126
+
127
+ await asyncio.sleep(SLEEP_BETWEEN_OPS)
128
+
129
+ # 4. Rename pages (remove '- 88716694' suffix)
130
+ print(f"\n[Step 4] Renaming {len(PAGES_TO_RENAME)} pages (remove '- 88716694' suffix)...")
131
+ rename_success = 0
132
+ rename_fail = 0
133
+
134
+ for page_id, new_title in PAGES_TO_RENAME:
135
+ page_info = await client.get_page(page_id, expand="version")
136
+ current_title = page_info.get("title", page_id) if page_info else page_id
137
+
138
+ print(f"\n Renaming: {current_title!r}")
139
+ print(f" page_id={page_id} -> new title: {new_title!r}")
140
+
141
+ try:
142
+ result = await client.rename_page(page_id, new_title)
143
+ print(f" [OK] Renamed successfully (result keys={list(result.keys()) if result else result!r})")
144
+ rename_success += 1
145
+ except Exception as exc:
146
+ print(f" [FAIL] Exception: {exc}")
147
+ print(" Waiting 30s and retrying once...")
148
+ await asyncio.sleep(30)
149
+ try:
150
+ result = await client.rename_page(page_id, new_title)
151
+ print(" [OK] Renamed on retry")
152
+ rename_success += 1
153
+ except Exception as exc2:
154
+ print(f" [FAIL] Retry also failed: {exc2}")
155
+ rename_fail += 1
156
+ continue
157
+
158
+ await asyncio.sleep(SLEEP_BETWEEN_OPS)
159
+
160
+ # 5. Archive duplicate
161
+ print(f"\n[Step 5] Archiving duplicate page {ARCHIVE_PAGE[0]}...")
162
+ archive_id, archive_new_title, archive_parent_id = ARCHIVE_PAGE
163
+ archive_parent_title = parent_titles[archive_parent_id]
164
+
165
+ page_info = await client.get_page(archive_id, expand="version")
166
+ current_title = page_info.get("title", archive_id) if page_info else archive_id
167
+ print(f" Current title: {current_title!r}")
168
+ print(f" New title: {archive_new_title!r}")
169
+ print(f" Target parent: {archive_parent_id} ({archive_parent_title!r})")
170
+
171
+ archive_success = True
172
+
173
+ # Step 5a: Rename first
174
+ try:
175
+ result = await client.rename_page(archive_id, archive_new_title)
176
+ print(" [OK] Renamed archive page")
177
+ except Exception as exc:
178
+ print(f" [FAIL] Could not rename archive page: {exc}")
179
+ archive_success = False
180
+
181
+ if archive_success:
182
+ await asyncio.sleep(SLEEP_BETWEEN_OPS)
183
+ # Step 5b: Move to archive parent
184
+ try:
185
+ result = await client.move_page(archive_id, archive_parent_title, position="append")
186
+ print(f" [OK] Moved archive page to {archive_parent_title!r}")
187
+ except Exception as exc:
188
+ print(f" [FAIL] Could not move archive page: {exc}")
189
+ print(" Waiting 30s and retrying once...")
190
+ await asyncio.sleep(30)
191
+ try:
192
+ result = await client.move_page(archive_id, archive_parent_title, position="append")
193
+ print(" [OK] Moved archive page on retry")
194
+ except Exception as exc2:
195
+ print(f" [FAIL] Retry also failed: {exc2}")
196
+ archive_success = False
197
+
198
+ # 6. Summary
199
+ print("\n" + "=" * 70)
200
+ print("SUMMARY")
201
+ print("=" * 70)
202
+ print(f" Moves: {move_success} succeeded, {move_fail} failed (of {len(PAGES_TO_MOVE)})")
203
+ print(f" Renames: {rename_success} succeeded, {rename_fail} failed (of {len(PAGES_TO_RENAME)})")
204
+ print(f" Archive: {'OK' if archive_success else 'FAILED'}")
205
+
206
+ total_failures = move_fail + rename_fail + (0 if archive_success else 1)
207
+ if total_failures > 0:
208
+ print(f"\n[WARN] {total_failures} operation(s) failed. Review output above.")
209
+ else:
210
+ print("\n[OK] All operations completed successfully.")
211
+
212
+ return 0 if total_failures == 0 else 1
213
+
214
+
215
+ if __name__ == "__main__":
216
+ sys.exit(asyncio.run(main()))