@ngocsangairvds/vsaf 4.1.8 → 4.1.9

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 (1065) hide show
  1. package/package.json +1 -1
  2. package/packages/cli/dist/commands/skill.js +1 -1
  3. package/packages/cli/dist/commands/skill.js.map +1 -1
  4. package/skills/vds-skill/_shared/config-check.js +0 -76
  5. package/skills/vds-skill/_shared/credentials.js +0 -139
  6. package/skills/vds-skill/create-bitbucket-pr/SKILL.md +0 -57
  7. package/skills/vds-skill/create-bitbucket-pr/scripts/create-pr.js +0 -125
  8. package/skills/vds-skill/create-jira-epic/SKILL.md +0 -55
  9. package/skills/vds-skill/create-jira-epic/scripts/create-epic.js +0 -120
  10. package/skills/vds-skill/install-deps.mjs +0 -567
  11. package/skills/vds-skill/pack.yaml +0 -24
  12. package/skills/vds-skill/pull/SKILL.md +0 -38
  13. package/skills/vds-skill/pull/scripts/pull.js +0 -59
  14. package/skills/vds-skill/push-prd/SKILL.md +0 -227
  15. package/skills/vds-skill/push-srs/SKILL.md +0 -116
  16. package/skills/vds-skill/search-confluence/SKILL.md +0 -53
  17. package/skills/vds-skill/search-confluence/scripts/search.js +0 -114
  18. package/skills/vds-skill/vds-scripts/.claude/phase7-CLOSURE.md +0 -100
  19. package/skills/vds-skill/vds-scripts/.dockerignore +0 -62
  20. package/skills/vds-skill/vds-scripts/.github/ISSUE_TEMPLATE/cli-change.md +0 -92
  21. package/skills/vds-skill/vds-scripts/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -48
  22. package/skills/vds-skill/vds-scripts/.github/workflows/chaos-smoke.yml +0 -266
  23. package/skills/vds-skill/vds-scripts/.github/workflows/confluence-sync.yml +0 -44
  24. package/skills/vds-skill/vds-scripts/.github/workflows/docs-confluence-evidence.yml +0 -170
  25. package/skills/vds-skill/vds-scripts/.github/workflows/docs-quality.yml +0 -59
  26. package/skills/vds-skill/vds-scripts/.github/workflows/lint-and-test.yml +0 -90
  27. package/skills/vds-skill/vds-scripts/.github/workflows/scheduler-load-smoke.yml +0 -104
  28. package/skills/vds-skill/vds-scripts/.github/workflows/telegram-bridge-ci.yml +0 -131
  29. package/skills/vds-skill/vds-scripts/.graphifyignore +0 -29
  30. package/skills/vds-skill/vds-scripts/.importlinter +0 -86
  31. package/skills/vds-skill/vds-scripts/.mcp.json +0 -11
  32. package/skills/vds-skill/vds-scripts/.pre-commit-config.yaml +0 -62
  33. package/skills/vds-skill/vds-scripts/.ruffignore +0 -3
  34. package/skills/vds-skill/vds-scripts/.secrets.baseline +0 -133
  35. package/skills/vds-skill/vds-scripts/AGENTS.md +0 -250
  36. package/skills/vds-skill/vds-scripts/AGENTS.vi.md +0 -92
  37. package/skills/vds-skill/vds-scripts/ECOSYSTEM-CHANGELOG.md +0 -52
  38. package/skills/vds-skill/vds-scripts/ECOSYSTEM-DOCS.md +0 -602
  39. package/skills/vds-skill/vds-scripts/ECOSYSTEM_ALIGNMENT.md +0 -133
  40. package/skills/vds-skill/vds-scripts/Makefile +0 -119
  41. package/skills/vds-skill/vds-scripts/README.md +0 -103
  42. package/skills/vds-skill/vds-scripts/bitbucket_manifest_mapping.toml +0 -34
  43. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/ARCHITECTURE_ANALYSIS.md +0 -258
  44. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/BITBUCKET_API_PRACTICES.md +0 -393
  45. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/EVALUATION_REPORT.md +0 -61
  46. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/FEATURES.md +0 -908
  47. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/README.md +0 -817
  48. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/pyproject.toml +0 -49
  49. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/__init__.py +0 -50
  50. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/async_client.py +0 -641
  51. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/cli.py +0 -2271
  52. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/client.py +0 -2693
  53. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/config.py +0 -186
  54. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/errors.py +0 -34
  55. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/factory.py +0 -185
  56. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/parsers.py +0 -113
  57. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/protocols.py +0 -244
  58. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/repo_ops.py +0 -325
  59. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/__init__.py +0 -8
  60. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/conftest.py +0 -65
  61. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_advanced_search.py +0 -155
  62. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_async_client.py +0 -505
  63. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_branch_permissions.py +0 -172
  64. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_cli.py +0 -113
  65. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_cli_archive.py +0 -122
  66. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_cli_clone.py +0 -131
  67. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_client.py +0 -207
  68. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_client_archive.py +0 -73
  69. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_client_branch_conditions.py +0 -101
  70. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_client_code_advanced.py +0 -180
  71. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_client_code_file.py +0 -33
  72. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_client_deployment_environments.py +0 -193
  73. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_client_issues.py +0 -163
  74. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_client_pipelines_advanced.py +0 -171
  75. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_client_pr_blockers.py +0 -118
  76. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_client_repository_variables.py +0 -155
  77. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_code.py +0 -98
  78. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_code_advanced.py +0 -279
  79. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_code_insights.py +0 -334
  80. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_conditions.py +0 -149
  81. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_config.py +0 -297
  82. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_deployment_env.py +0 -352
  83. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_errors.py +0 -67
  84. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_factory.py +0 -352
  85. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_fork_operations.py +0 -203
  86. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_issue_cli.py +0 -262
  87. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_pipeline_advanced.py +0 -265
  88. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_pr_blocker.py +0 -206
  89. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_protocols.py +0 -336
  90. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_repo_ops_archive.py +0 -169
  91. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_repo_ops_clone.py +0 -115
  92. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_repo_ops_parsing.py +0 -149
  93. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_repo_settings.py +0 -336
  94. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_repo_variables.py +0 -266
  95. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_webhooks.py +0 -188
  96. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/test_workspace.py +0 -234
  97. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/unit/__init__.py +0 -0
  98. package/skills/vds-skill/vds-scripts/bitbucket_orchestrator/tests/unit/test_parsers.py +0 -254
  99. package/skills/vds-skill/vds-scripts/brd_orchestrator/README.md +0 -29
  100. package/skills/vds-skill/vds-scripts/brd_orchestrator/pyproject.toml +0 -63
  101. package/skills/vds-skill/vds-scripts/brd_orchestrator/src/vds_brd_orchestrator/__init__.py +0 -17
  102. package/skills/vds-skill/vds-scripts/brd_orchestrator/src/vds_brd_orchestrator/cli.py +0 -187
  103. package/skills/vds-skill/vds-scripts/brd_orchestrator/src/vds_brd_orchestrator/validator.py +0 -121
  104. package/skills/vds-skill/vds-scripts/brd_orchestrator/tests/__init__.py +0 -0
  105. package/skills/vds-skill/vds-scripts/brd_orchestrator/tests/test_cli.py +0 -62
  106. package/skills/vds-skill/vds-scripts/brd_orchestrator/tests/test_validator.py +0 -33
  107. package/skills/vds-skill/vds-scripts/code/code_evidence_pack.json +0 -435
  108. package/skills/vds-skill/vds-scripts/confluence_orchestrator/Dockerfile +0 -19
  109. package/skills/vds-skill/vds-scripts/confluence_orchestrator/README.md +0 -479
  110. package/skills/vds-skill/vds-scripts/confluence_orchestrator/SYNC_SCRIPTS.md +0 -127
  111. package/skills/vds-skill/vds-scripts/confluence_orchestrator/SYNC_STANDARDIZATION.md +0 -108
  112. package/skills/vds-skill/vds-scripts/confluence_orchestrator/pyproject.toml +0 -50
  113. package/skills/vds-skill/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/__init__.py +0 -56
  114. package/skills/vds-skill/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/async_client.py +0 -100
  115. package/skills/vds-skill/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/cli.py +0 -3160
  116. package/skills/vds-skill/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/config.py +0 -215
  117. package/skills/vds-skill/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/content.py +0 -368
  118. package/skills/vds-skill/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/content_v2.py +0 -144
  119. package/skills/vds-skill/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/crawl_tree.py +0 -1833
  120. package/skills/vds-skill/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/errors.py +0 -44
  121. package/skills/vds-skill/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/eventing.py +0 -111
  122. package/skills/vds-skill/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/http.py +0 -1850
  123. package/skills/vds-skill/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/orchestration.py +0 -166
  124. package/skills/vds-skill/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/protocols.py +0 -61
  125. package/skills/vds-skill/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/reporting.py +0 -78
  126. package/skills/vds-skill/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/tree.py +0 -122
  127. package/skills/vds-skill/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/tree_copier.py +0 -431
  128. package/skills/vds-skill/vds-scripts/confluence_orchestrator/sync_pdfs_from_markdown.py +0 -203
  129. package/skills/vds-skill/vds-scripts/confluence_orchestrator/sync_pdfs_to_confluence.py +0 -299
  130. package/skills/vds-skill/vds-scripts/confluence_orchestrator/sync_png_attachments.py +0 -299
  131. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/conftest.py +0 -46
  132. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_advanced_content.py +0 -252
  133. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_advanced_search.py +0 -193
  134. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_async_client.py +0 -104
  135. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_cache_management.py +0 -246
  136. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_cli.py +0 -716
  137. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_config.py +0 -130
  138. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_content.py +0 -192
  139. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_content_flags.py +0 -27
  140. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_content_labels.py +0 -94
  141. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_crawl_tree.py +0 -2252
  142. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_degraded_write_safety.py +0 -176
  143. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_draft_management.py +0 -225
  144. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_errors.py +0 -75
  145. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_eventing.py +0 -73
  146. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_eventing_chaos.py +0 -37
  147. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_eventing_rate_limit.py +0 -44
  148. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_eventing_timeout.py +0 -49
  149. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_export.py +0 -231
  150. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_history.py +0 -217
  151. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_http.py +0 -375
  152. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_orchestration.py +0 -93
  153. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_reporting.py +0 -24
  154. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_search_cql.py +0 -36
  155. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_space_management.py +0 -236
  156. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_space_permissions.py +0 -384
  157. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_tree_copier.py +0 -644
  158. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_tree_copier_remap.py +0 -289
  159. package/skills/vds-skill/vds-scripts/confluence_orchestrator/tests/test_user_group_management.py +0 -387
  160. package/skills/vds-skill/vds-scripts/diagram_generator/README.md +0 -663
  161. package/skills/vds-skill/vds-scripts/diagram_generator/ci_validate.sh +0 -16
  162. package/skills/vds-skill/vds-scripts/diagram_generator/docs-nttc/projects/INSURANCE/analysis/current-state/insurance-claim-business/insurance-claim-business-component.png +0 -0
  163. package/skills/vds-skill/vds-scripts/diagram_generator/docs-nttc/projects/INSURANCE/analysis/current-state/insurance-claim-business/insurance-claim-business-component.puml +0 -23
  164. package/skills/vds-skill/vds-scripts/diagram_generator/docs-nttc/projects/INSURANCE/analysis/current-state/insurance-claim-business/insurance-claim-business-sequence.png +0 -0
  165. package/skills/vds-skill/vds-scripts/diagram_generator/docs-nttc/projects/INSURANCE/analysis/current-state/insurance-claim-business/insurance-claim-business-sequence.puml +0 -21
  166. package/skills/vds-skill/vds-scripts/diagram_generator/docs-nttc/projects/INSURANCE/analysis/current-state/insurance-claim-business/insurance-claim-business-usecase.png +0 -0
  167. package/skills/vds-skill/vds-scripts/diagram_generator/docs-nttc/projects/INSURANCE/analysis/current-state/insurance-claim-business/insurance-claim-business-usecase.puml +0 -14
  168. package/skills/vds-skill/vds-scripts/diagram_generator/examples/github-actions-validate.yml +0 -39
  169. package/skills/vds-skill/vds-scripts/diagram_generator/generate_all_diagrams.py +0 -827
  170. package/skills/vds-skill/vds-scripts/diagram_generator/generate_insurance_c4_diagrams.py +0 -261
  171. package/skills/vds-skill/vds-scripts/diagram_generator/generate_insurance_c4_quick.py +0 -486
  172. package/skills/vds-skill/vds-scripts/diagram_generator/pyproject.toml +0 -28
  173. package/skills/vds-skill/vds-scripts/diagram_generator/render_png.py +0 -59
  174. package/skills/vds-skill/vds-scripts/diagram_generator/src/vds_diagram_generator/__init__.py +0 -3
  175. package/skills/vds-skill/vds-scripts/diagram_generator/src/vds_diagram_generator/cli.py +0 -50
  176. package/skills/vds-skill/vds-scripts/diagram_generator/test_c4_hierarchical.py +0 -142
  177. package/skills/vds-skill/vds-scripts/diagram_generator/test_c4_quick.py +0 -131
  178. package/skills/vds-skill/vds-scripts/diagram_generator/tests/__init__.py +0 -0
  179. package/skills/vds-skill/vds-scripts/diagram_generator/tests/test_analyzer_completeness.py +0 -260
  180. package/skills/vds-skill/vds-scripts/diagram_generator/tests/test_c4_syntax_correctness.py +0 -138
  181. package/skills/vds-skill/vds-scripts/diagram_generator/tests/test_component_coverage.py +0 -182
  182. package/skills/vds-skill/vds-scripts/diagram_generator/tests/test_mermaid_output.py +0 -80
  183. package/skills/vds-skill/vds-scripts/diagram_generator/tests/test_png_generation.py +0 -112
  184. package/skills/vds-skill/vds-scripts/diagram_generator/tests/test_scenario_templates.py +0 -15
  185. package/skills/vds-skill/vds-scripts/diagram_generator/tests/test_sequence_accuracy.py +0 -93
  186. package/skills/vds-skill/vds-scripts/diagram_generator/tests/test_structurizr_export.py +0 -177
  187. package/skills/vds-skill/vds-scripts/diagram_generator/tests/test_style_consistency.py +0 -174
  188. package/skills/vds-skill/vds-scripts/diagram_generator/tests/test_usecase_generator.py +0 -201
  189. package/skills/vds-skill/vds-scripts/diagram_generator/tests/test_usecase_integration.py +0 -124
  190. package/skills/vds-skill/vds-scripts/docker/.dockerignore +0 -38
  191. package/skills/vds-skill/vds-scripts/docker/ADR.md +0 -392
  192. package/skills/vds-skill/vds-scripts/docker/Dockerfile +0 -68
  193. package/skills/vds-skill/vds-scripts/docker/MIGRATION.md +0 -453
  194. package/skills/vds-skill/vds-scripts/docker/README.md +0 -347
  195. package/skills/vds-skill/vds-scripts/docker/ROLLBACK.md +0 -596
  196. package/skills/vds-skill/vds-scripts/docker/compose.phase2-verification.yml +0 -31
  197. package/skills/vds-skill/vds-scripts/docker/docker-compose.cli.yml +0 -206
  198. package/skills/vds-skill/vds-scripts/docker/docker-compose.infra.yml +0 -276
  199. package/skills/vds-skill/vds-scripts/docker/docker-compose.services.yml +0 -425
  200. package/skills/vds-skill/vds-scripts/docker/infrastructure/init-schemas.sql +0 -177
  201. package/skills/vds-skill/vds-scripts/docker/infrastructure/pgbouncer/pgbouncer.ini +0 -75
  202. package/skills/vds-skill/vds-scripts/docker/infrastructure/pgbouncer/userlist.txt +0 -50
  203. package/skills/vds-skill/vds-scripts/docker/infrastructure/pgbouncer/userlist.txt.template +0 -36
  204. package/skills/vds-skill/vds-scripts/docs/.confluence-evidence/.gitkeep +0 -0
  205. package/skills/vds-skill/vds-scripts/docs/.confluence-evidence/PREFLIGHT.md +0 -132
  206. package/skills/vds-skill/vds-scripts/docs/.confluence-evidence/README.md +0 -84
  207. package/skills/vds-skill/vds-scripts/docs/.confluence.yaml +0 -157
  208. package/skills/vds-skill/vds-scripts/docs/.freshness.yaml +0 -54
  209. package/skills/vds-skill/vds-scripts/docs/README.md +0 -235
  210. package/skills/vds-skill/vds-scripts/docs/agents/README.md +0 -33
  211. package/skills/vds-skill/vds-scripts/docs/agents/explanation/data-flow.md +0 -132
  212. package/skills/vds-skill/vds-scripts/docs/agents/explanation/development-roadmap.md +0 -49
  213. package/skills/vds-skill/vds-scripts/docs/agents/explanation/features-overview.md +0 -62
  214. package/skills/vds-skill/vds-scripts/docs/agents/explanation/index.md +0 -36
  215. package/skills/vds-skill/vds-scripts/docs/agents/explanation/runtime-verification-and-gap-reporting.md +0 -127
  216. package/skills/vds-skill/vds-scripts/docs/agents/explanation/system-architecture.md +0 -139
  217. package/skills/vds-skill/vds-scripts/docs/agents/explanation/whats-new.md +0 -75
  218. package/skills/vds-skill/vds-scripts/docs/agents/explanation/who-ecosystem-introduction.md +0 -65
  219. package/skills/vds-skill/vds-scripts/docs/agents/explanation/who-ecosystem-model.md +0 -41
  220. package/skills/vds-skill/vds-scripts/docs/agents/how-to/02-using-vds-ai-memory.md +0 -98
  221. package/skills/vds-skill/vds-scripts/docs/agents/how-to/03-memory-cross-agent.md +0 -241
  222. package/skills/vds-skill/vds-scripts/docs/agents/how-to/04-using-progress-reports.md +0 -240
  223. package/skills/vds-skill/vds-scripts/docs/agents/how-to/08-semantic-search.md +0 -46
  224. package/skills/vds-skill/vds-scripts/docs/agents/how-to/apply-phase3-migration.md +0 -148
  225. package/skills/vds-skill/vds-scripts/docs/agents/how-to/choose-the-right-command-or-skill.md +0 -34
  226. package/skills/vds-skill/vds-scripts/docs/agents/how-to/contribute-new-orchestrator.md +0 -149
  227. package/skills/vds-skill/vds-scripts/docs/agents/how-to/decision-tree.md +0 -63
  228. package/skills/vds-skill/vds-scripts/docs/agents/how-to/first-audit-run.md +0 -83
  229. package/skills/vds-skill/vds-scripts/docs/agents/how-to/index.md +0 -49
  230. package/skills/vds-skill/vds-scripts/docs/agents/how-to/install-and-bootstrap-who-scripts-and-skills.md +0 -314
  231. package/skills/vds-skill/vds-scripts/docs/agents/how-to/orchestrator-workflows/analytics-pipeline-workflow.md +0 -165
  232. package/skills/vds-skill/vds-scripts/docs/agents/how-to/orchestrator-workflows/code-quality-gate-workflow.md +0 -138
  233. package/skills/vds-skill/vds-scripts/docs/agents/how-to/orchestrator-workflows/confluence-bitbucket-sync-workflow.md +0 -130
  234. package/skills/vds-skill/vds-scripts/docs/agents/how-to/orchestrator-workflows/document-delivery-workflow.md +0 -142
  235. package/skills/vds-skill/vds-scripts/docs/agents/how-to/orchestrator-workflows/memory-progress-workflow.md +0 -140
  236. package/skills/vds-skill/vds-scripts/docs/agents/how-to/orchestrator-workflows/research-spec-audit-workflow.md +0 -135
  237. package/skills/vds-skill/vds-scripts/docs/agents/how-to/phase131-all-project-preparation.md +0 -211
  238. package/skills/vds-skill/vds-scripts/docs/agents/how-to/phase131-bounded-parallel-analysis.md +0 -123
  239. package/skills/vds-skill/vds-scripts/docs/agents/how-to/phase131-confluence-upload-recovery.md +0 -204
  240. package/skills/vds-skill/vds-scripts/docs/agents/how-to/phase132-department-preparation.md +0 -144
  241. package/skills/vds-skill/vds-scripts/docs/agents/how-to/run-ecosystem-daily-report.md +0 -213
  242. package/skills/vds-skill/vds-scripts/docs/agents/how-to/tips-and-tricks.md +0 -138
  243. package/skills/vds-skill/vds-scripts/docs/agents/how-to/troubleshooting-guide.md +0 -221
  244. package/skills/vds-skill/vds-scripts/docs/agents/reference/agent-operational-contract.md +0 -162
  245. package/skills/vds-skill/vds-scripts/docs/agents/reference/alignment-phase179-report.md +0 -144
  246. package/skills/vds-skill/vds-scripts/docs/agents/reference/audit-triage-playbook.md +0 -256
  247. package/skills/vds-skill/vds-scripts/docs/agents/reference/backup-restore.md +0 -132
  248. package/skills/vds-skill/vds-scripts/docs/agents/reference/bitbucket-orchestrator.md +0 -56
  249. package/skills/vds-skill/vds-scripts/docs/agents/reference/brd-orchestrator.md +0 -52
  250. package/skills/vds-skill/vds-scripts/docs/agents/reference/capability-coverage-review.md +0 -51
  251. package/skills/vds-skill/vds-scripts/docs/agents/reference/ci-workflows.md +0 -98
  252. package/skills/vds-skill/vds-scripts/docs/agents/reference/circular-dependency-orchestrator.md +0 -55
  253. package/skills/vds-skill/vds-scripts/docs/agents/reference/cli-commands.md +0 -583
  254. package/skills/vds-skill/vds-scripts/docs/agents/reference/cli-development-standards.md +0 -41
  255. package/skills/vds-skill/vds-scripts/docs/agents/reference/cli-help-matrix.md +0 -84
  256. package/skills/vds-skill/vds-scripts/docs/agents/reference/common-errors.md +0 -126
  257. package/skills/vds-skill/vds-scripts/docs/agents/reference/configuration-reference.md +0 -128
  258. package/skills/vds-skill/vds-scripts/docs/agents/reference/confluence-orchestrator.md +0 -56
  259. package/skills/vds-skill/vds-scripts/docs/agents/reference/confluence-sync-target.md +0 -111
  260. package/skills/vds-skill/vds-scripts/docs/agents/reference/confluence-sync.md +0 -46
  261. package/skills/vds-skill/vds-scripts/docs/agents/reference/db-query-orchestrator.md +0 -93
  262. package/skills/vds-skill/vds-scripts/docs/agents/reference/diagrams-orchestrator.md +0 -52
  263. package/skills/vds-skill/vds-scripts/docs/agents/reference/ecosystem-daily-report.md +0 -229
  264. package/skills/vds-skill/vds-scripts/docs/agents/reference/elastic-orchestrator.md +0 -57
  265. package/skills/vds-skill/vds-scripts/docs/agents/reference/env-git-helper.md +0 -216
  266. package/skills/vds-skill/vds-scripts/docs/agents/reference/evolution-orchestrator.md +0 -113
  267. package/skills/vds-skill/vds-scripts/docs/agents/reference/excel-orchestrator.md +0 -51
  268. package/skills/vds-skill/vds-scripts/docs/agents/reference/git-orchestrator.md +0 -62
  269. package/skills/vds-skill/vds-scripts/docs/agents/reference/google-sheets-orchestrator.md +0 -51
  270. package/skills/vds-skill/vds-scripts/docs/agents/reference/grafana-orchestrator.md +0 -52
  271. package/skills/vds-skill/vds-scripts/docs/agents/reference/hexagonal-orchestrator.md +0 -64
  272. package/skills/vds-skill/vds-scripts/docs/agents/reference/index.md +0 -36
  273. package/skills/vds-skill/vds-scripts/docs/agents/reference/infrastructure-v2.15.md +0 -67
  274. package/skills/vds-skill/vds-scripts/docs/agents/reference/intellij-orchestrator.md +0 -50
  275. package/skills/vds-skill/vds-scripts/docs/agents/reference/jira-orchestrator.md +0 -60
  276. package/skills/vds-skill/vds-scripts/docs/agents/reference/links-orchestrator.md +0 -57
  277. package/skills/vds-skill/vds-scripts/docs/agents/reference/lint-cli.md +0 -99
  278. package/skills/vds-skill/vds-scripts/docs/agents/reference/lsp-orchestrator.md +0 -51
  279. package/skills/vds-skill/vds-scripts/docs/agents/reference/markdown-orchestrator.md +0 -53
  280. package/skills/vds-skill/vds-scripts/docs/agents/reference/mcp-orchestrator.md +0 -88
  281. package/skills/vds-skill/vds-scripts/docs/agents/reference/memory-orchestrator.md +0 -53
  282. package/skills/vds-skill/vds-scripts/docs/agents/reference/metabase-orchestrator.md +0 -51
  283. package/skills/vds-skill/vds-scripts/docs/agents/reference/migration-playbook.md +0 -71
  284. package/skills/vds-skill/vds-scripts/docs/agents/reference/multi-agent-orchestrator.md +0 -52
  285. package/skills/vds-skill/vds-scripts/docs/agents/reference/openapi-orchestrator.md +0 -57
  286. package/skills/vds-skill/vds-scripts/docs/agents/reference/orchestrator-architecture.md +0 -194
  287. package/skills/vds-skill/vds-scripts/docs/agents/reference/orchestrator-comparison-matrix.md +0 -79
  288. package/skills/vds-skill/vds-scripts/docs/agents/reference/orchestrator-index.md +0 -73
  289. package/skills/vds-skill/vds-scripts/docs/agents/reference/pdf-orchestrator.md +0 -57
  290. package/skills/vds-skill/vds-scripts/docs/agents/reference/portable-paths-and-config.md +0 -0
  291. package/skills/vds-skill/vds-scripts/docs/agents/reference/portable-paths-validation-matrix.md +0 -129
  292. package/skills/vds-skill/vds-scripts/docs/agents/reference/progress-orchestrator.md +0 -51
  293. package/skills/vds-skill/vds-scripts/docs/agents/reference/progress-report-cli.md +0 -215
  294. package/skills/vds-skill/vds-scripts/docs/agents/reference/public-interface-orchestrator.md +0 -73
  295. package/skills/vds-skill/vds-scripts/docs/agents/reference/research-orchestrator.md +0 -53
  296. package/skills/vds-skill/vds-scripts/docs/agents/reference/schema-orchestrator.md +0 -57
  297. package/skills/vds-skill/vds-scripts/docs/agents/reference/search-tools.md +0 -34
  298. package/skills/vds-skill/vds-scripts/docs/agents/reference/skills-commands.md +0 -256
  299. package/skills/vds-skill/vds-scripts/docs/agents/reference/skills-reference.md +0 -32
  300. package/skills/vds-skill/vds-scripts/docs/agents/reference/sonarqube-orchestrator.md +0 -62
  301. package/skills/vds-skill/vds-scripts/docs/agents/reference/spec-orchestrator.md +0 -56
  302. package/skills/vds-skill/vds-scripts/docs/agents/reference/structure-orchestrator.md +0 -69
  303. package/skills/vds-skill/vds-scripts/docs/agents/reference/system-requirements.md +0 -76
  304. package/skills/vds-skill/vds-scripts/docs/agents/reference/tasks-orchestrator.md +0 -53
  305. package/skills/vds-skill/vds-scripts/docs/agents/reference/validation-and-sync-notes.md +0 -54
  306. package/skills/vds-skill/vds-scripts/docs/agents/reference/vds-ai-memory-api.md +0 -51
  307. package/skills/vds-skill/vds-scripts/docs/agents/reference/vds-cli-reference.md +0 -34
  308. package/skills/vds-skill/vds-scripts/docs/agents/reference/who-capability-inventory.md +0 -96
  309. package/skills/vds-skill/vds-scripts/docs/agents/reference/who-capability-routing-matrix.md +0 -14
  310. package/skills/vds-skill/vds-scripts/docs/agents/tutorials/feature-progression-guide.md +0 -112
  311. package/skills/vds-skill/vds-scripts/docs/agents/tutorials/index.md +0 -36
  312. package/skills/vds-skill/vds-scripts/docs/agents/tutorials/quick-start.md +0 -50
  313. package/skills/vds-skill/vds-scripts/docs/agents/tutorials/who-skills-and-scripts-onboarding.md +0 -47
  314. package/skills/vds-skill/vds-scripts/docs/agents/tutorials/zero-to-productive-developer.md +0 -339
  315. package/skills/vds-skill/vds-scripts/docs/confluence/IMPLEMENTATION-SUMMARY.md +0 -78
  316. package/skills/vds-skill/vds-scripts/docs/confluence/SYNC-GUIDE.md +0 -47
  317. package/skills/vds-skill/vds-scripts/docs/deployment/offline-docker-image-load.md +0 -59
  318. package/skills/vds-skill/vds-scripts/docs/evolution-auto-run-rollout.md +0 -325
  319. package/skills/vds-skill/vds-scripts/docs/evolution-loop-deep-integration.md +0 -496
  320. package/skills/vds-skill/vds-scripts/docs/evolution-loop-integration-guide.md +0 -359
  321. package/skills/vds-skill/vds-scripts/docs/openspace-schema-snapshot.md +0 -73
  322. package/skills/vds-skill/vds-scripts/docs/operations/sla-mttr-policy.md +0 -44
  323. package/skills/vds-skill/vds-scripts/docs/p0-closure-evidence/SUMMARY.md +0 -58
  324. package/skills/vds-skill/vds-scripts/docs/p4-closure-evidence/.gitkeep +0 -0
  325. package/skills/vds-skill/vds-scripts/docs/p4-closure-evidence/smoke-20260427T024137Z-b95b586b.json +0 -15
  326. package/skills/vds-skill/vds-scripts/docs/p8-preflight-evidence/alembic-and-runtime-advisory-locks.md +0 -45
  327. package/skills/vds-skill/vds-scripts/docs/p8-preflight-evidence/dbos-listen-notify.md +0 -54
  328. package/skills/vds-skill/vds-scripts/docs/p8-preflight-evidence/pgbouncer-search-path-empirical.md +0 -110
  329. package/skills/vds-skill/vds-scripts/docs/p8-preflight-evidence/pgvector-set-local-audit.md +0 -51
  330. package/skills/vds-skill/vds-scripts/docs/p8-preflight-evidence/topology-decision-session-mode.md +0 -57
  331. package/skills/vds-skill/vds-scripts/docs/phases/CHANGELOG.md +0 -103
  332. package/skills/vds-skill/vds-scripts/docs/phases/PHASE_125_COMPLETION_AND_MERGE.md +0 -212
  333. package/skills/vds-skill/vds-scripts/docs/phases/phase125/IMPLEMENTATION_REPORT.md +0 -227
  334. package/skills/vds-skill/vds-scripts/docs/phases/phase125/TSK-125.10-11-implementation-summary.md +0 -196
  335. package/skills/vds-skill/vds-scripts/docs/phases/phase125/profile-patch-ollama-local-anthropic.md +0 -122
  336. package/skills/vds-skill/vds-scripts/docs/phases/phase125_completion_summary.md +0 -369
  337. package/skills/vds-skill/vds-scripts/docs/phases/phase125_llm_analysis_skill.md +0 -164
  338. package/skills/vds-skill/vds-scripts/docs/phases/phase125_merge_complete.md +0 -147
  339. package/skills/vds-skill/vds-scripts/docs/phases/phase125_skill_runtime_closure_20260321.md +0 -91
  340. package/skills/vds-skill/vds-scripts/docs/phases/phase2-portable-paths/closure-handoff-summary-2026-03-23.md +0 -290
  341. package/skills/vds-skill/vds-scripts/docs/phases/phase2-portable-paths/remaining-risk-register-2026-03-25.md +0 -143
  342. package/skills/vds-skill/vds-scripts/docs/phases/phase2-portable-paths/verification-evidence-2026-03-23.md +0 -135
  343. package/skills/vds-skill/vds-scripts/docs/v0-sunset-known-issues.md +0 -88
  344. package/skills/vds-skill/vds-scripts/docs/vi/TRANSLATION-BACKLOG.md +0 -72
  345. package/skills/vds-skill/vds-scripts/docs/vi/agents/README.md +0 -41
  346. package/skills/vds-skill/vds-scripts/docs/vi/agents/explanation/features-overview.md +0 -29
  347. package/skills/vds-skill/vds-scripts/docs/vi/agents/explanation/index.md +0 -14
  348. package/skills/vds-skill/vds-scripts/docs/vi/agents/explanation/runtime-verification-and-gap-reporting.md +0 -129
  349. package/skills/vds-skill/vds-scripts/docs/vi/agents/explanation/whats-new.md +0 -37
  350. package/skills/vds-skill/vds-scripts/docs/vi/agents/explanation/who-ecosystem-introduction.md +0 -21
  351. package/skills/vds-skill/vds-scripts/docs/vi/agents/explanation/who-ecosystem-model.md +0 -36
  352. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/02-using-vds-ai-memory.md +0 -100
  353. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/03-memory-cross-agent.md +0 -243
  354. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/04-using-progress-reports.md +0 -242
  355. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/08-semantic-search.md +0 -16
  356. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/choose-the-right-command-or-skill.md +0 -36
  357. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/decision-tree.md +0 -77
  358. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/first-audit-run.md +0 -85
  359. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/index.md +0 -21
  360. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/install-and-bootstrap-who-scripts-and-skills.md +0 -156
  361. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/orchestrator-workflows/analytics-pipeline-workflow.md +0 -174
  362. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/orchestrator-workflows/code-quality-gate-workflow.md +0 -147
  363. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/orchestrator-workflows/confluence-bitbucket-sync-workflow.md +0 -139
  364. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/orchestrator-workflows/document-delivery-workflow.md +0 -151
  365. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/orchestrator-workflows/memory-progress-workflow.md +0 -149
  366. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/orchestrator-workflows/research-spec-audit-workflow.md +0 -144
  367. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/phase131-all-project-preparation.md +0 -213
  368. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/phase131-bounded-parallel-analysis.md +0 -125
  369. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/phase131-confluence-upload-recovery.md +0 -206
  370. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/phase132-department-preparation.md +0 -146
  371. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/tips-and-tricks.md +0 -34
  372. package/skills/vds-skill/vds-scripts/docs/vi/agents/how-to/troubleshooting-guide.md +0 -36
  373. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/agent-operational-contract.md +0 -98
  374. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/audit-triage-playbook.md +0 -258
  375. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/bitbucket-orchestrator.md +0 -30
  376. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/brd-orchestrator.md +0 -29
  377. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/capability-coverage-review.md +0 -46
  378. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/circular-dependency-orchestrator.md +0 -29
  379. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/cli-commands.md +0 -409
  380. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/cli-development-standards.md +0 -19
  381. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/cli-help-matrix.md +0 -71
  382. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/common-errors.md +0 -133
  383. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/configuration-reference.md +0 -25
  384. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/confluence-orchestrator.md +0 -30
  385. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/db-query-orchestrator.md +0 -34
  386. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/diagrams-orchestrator.md +0 -31
  387. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/elastic-orchestrator.md +0 -30
  388. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/evolution-orchestrator.md +0 -31
  389. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/excel-orchestrator.md +0 -60
  390. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/git-orchestrator.md +0 -31
  391. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/google-sheets-orchestrator.md +0 -60
  392. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/grafana-orchestrator.md +0 -30
  393. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/hexagonal-orchestrator.md +0 -73
  394. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/index.md +0 -25
  395. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/intellij-orchestrator.md +0 -59
  396. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/jira-orchestrator.md +0 -32
  397. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/links-orchestrator.md +0 -66
  398. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/lsp-orchestrator.md +0 -60
  399. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/markdown-orchestrator.md +0 -62
  400. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/mcp-orchestrator.md +0 -34
  401. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/memory-orchestrator.md +0 -45
  402. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/metabase-orchestrator.md +0 -30
  403. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/multi-agent-orchestrator.md +0 -61
  404. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/openapi-orchestrator.md +0 -66
  405. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/orchestrator-architecture.md +0 -24
  406. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/orchestrator-index.md +0 -73
  407. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/pdf-orchestrator.md +0 -30
  408. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/portable-paths-and-config.md +0 -123
  409. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/portable-paths-validation-matrix.md +0 -131
  410. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/progress-orchestrator.md +0 -43
  411. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/progress-report-cli.md +0 -217
  412. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/public-interface-orchestrator.md +0 -82
  413. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/research-orchestrator.md +0 -45
  414. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/schema-orchestrator.md +0 -66
  415. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/search-tools.md +0 -19
  416. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/skills-reference.md +0 -27
  417. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/sonarqube-orchestrator.md +0 -71
  418. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/spec-orchestrator.md +0 -56
  419. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/structure-orchestrator.md +0 -78
  420. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/system-requirements.md +0 -30
  421. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/tasks-orchestrator.md +0 -45
  422. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/validation-and-sync-notes.md +0 -26
  423. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/vds-ai-memory-api.md +0 -53
  424. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/vds-cli-reference.md +0 -34
  425. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/who-capability-inventory.md +0 -98
  426. package/skills/vds-skill/vds-scripts/docs/vi/agents/reference/who-capability-routing-matrix.md +0 -16
  427. package/skills/vds-skill/vds-scripts/docs/vi/agents/tutorials/feature-progression-guide.md +0 -124
  428. package/skills/vds-skill/vds-scripts/docs/vi/agents/tutorials/index.md +0 -13
  429. package/skills/vds-skill/vds-scripts/docs/vi/agents/tutorials/quick-start.md +0 -30
  430. package/skills/vds-skill/vds-scripts/docs/vi/agents/tutorials/who-skills-and-scripts-onboarding.md +0 -42
  431. package/skills/vds-skill/vds-scripts/docs/vi/agents/tutorials/zero-to-productive-developer.md +0 -137
  432. package/skills/vds-skill/vds-scripts/elastic_orchestrator/README.md +0 -450
  433. package/skills/vds-skill/vds-scripts/elastic_orchestrator/pyproject.toml +0 -97
  434. package/skills/vds-skill/vds-scripts/elastic_orchestrator/src/vds_elastic_orchestrator/__init__.py +0 -81
  435. package/skills/vds-skill/vds-scripts/elastic_orchestrator/src/vds_elastic_orchestrator/cli.py +0 -652
  436. package/skills/vds-skill/vds-scripts/elastic_orchestrator/src/vds_elastic_orchestrator/client.py +0 -743
  437. package/skills/vds-skill/vds-scripts/elastic_orchestrator/src/vds_elastic_orchestrator/config.py +0 -208
  438. package/skills/vds-skill/vds-scripts/elastic_orchestrator/src/vds_elastic_orchestrator/errors.py +0 -34
  439. package/skills/vds-skill/vds-scripts/elastic_orchestrator/src/vds_elastic_orchestrator/py.typed +0 -0
  440. package/skills/vds-skill/vds-scripts/elastic_orchestrator/tests/__init__.py +0 -0
  441. package/skills/vds-skill/vds-scripts/elastic_orchestrator/tests/conftest.py +0 -227
  442. package/skills/vds-skill/vds-scripts/elastic_orchestrator/tests/test_client.py +0 -990
  443. package/skills/vds-skill/vds-scripts/elastic_orchestrator/tests/test_config.py +0 -268
  444. package/skills/vds-skill/vds-scripts/elastic_orchestrator/tests/test_e2e_verification.py +0 -272
  445. package/skills/vds-skill/vds-scripts/elastic_orchestrator/tests/test_errors.py +0 -78
  446. package/skills/vds-skill/vds-scripts/excel_orchestrator/README.md +0 -288
  447. package/skills/vds-skill/vds-scripts/excel_orchestrator/RESEARCH_BASED_UPDATES_REPORT.md +0 -261
  448. package/skills/vds-skill/vds-scripts/excel_orchestrator/add_essential_missing_effort.py +0 -255
  449. package/skills/vds-skill/vds-scripts/excel_orchestrator/adjust_effort_complexity.py +0 -184
  450. package/skills/vds-skill/vds-scripts/excel_orchestrator/brd_analysis_and_task_breakdown.py +0 -632
  451. package/skills/vds-skill/vds-scripts/excel_orchestrator/brd_analysis_comprehensive.py +0 -1029
  452. package/skills/vds-skill/vds-scripts/excel_orchestrator/check_overlaps_and_brd_coverage.py +0 -570
  453. package/skills/vds-skill/vds-scripts/excel_orchestrator/clean_remarks_column.py +0 -127
  454. package/skills/vds-skill/vds-scripts/excel_orchestrator/comprehensive_brd_check.py +0 -322
  455. package/skills/vds-skill/vds-scripts/excel_orchestrator/create_buffered_summary.py +0 -119
  456. package/skills/vds-skill/vds-scripts/excel_orchestrator/create_service_totals_sheet.py +0 -118
  457. package/skills/vds-skill/vds-scripts/excel_orchestrator/examples/basic_operations.py +0 -85
  458. package/skills/vds-skill/vds-scripts/excel_orchestrator/expand_all_tasks.py +0 -341
  459. package/skills/vds-skill/vds-scripts/excel_orchestrator/expand_tasks.py +0 -304
  460. package/skills/vds-skill/vds-scripts/excel_orchestrator/fill_brd_references.py +0 -347
  461. package/skills/vds-skill/vds-scripts/excel_orchestrator/fill_remarks_and_colors.py +0 -132
  462. package/skills/vds-skill/vds-scripts/excel_orchestrator/finalize_brd_and_cleanup.py +0 -295
  463. package/skills/vds-skill/vds-scripts/excel_orchestrator/finalize_brd_coverage.py +0 -327
  464. package/skills/vds-skill/vds-scripts/excel_orchestrator/fix_all_formulas.py +0 -99
  465. package/skills/vds-skill/vds-scripts/excel_orchestrator/fix_detail_presentation.py +0 -113
  466. package/skills/vds-skill/vds-scripts/excel_orchestrator/fix_presentation_and_effort.py +0 -116
  467. package/skills/vds-skill/vds-scripts/excel_orchestrator/fix_presentation_consistency.py +0 -231
  468. package/skills/vds-skill/vds-scripts/excel_orchestrator/fix_remarks_matching.py +0 -179
  469. package/skills/vds-skill/vds-scripts/excel_orchestrator/group_tasks_by_service_id.py +0 -210
  470. package/skills/vds-skill/vds-scripts/excel_orchestrator/increase_brd_coverage.py +0 -497
  471. package/skills/vds-skill/vds-scripts/excel_orchestrator/increase_effort_complexity.py +0 -155
  472. package/skills/vds-skill/vds-scripts/excel_orchestrator/organize_and_deduplicate.py +0 -273
  473. package/skills/vds-skill/vds-scripts/excel_orchestrator/pyproject.toml +0 -64
  474. package/skills/vds-skill/vds-scripts/excel_orchestrator/rebuild_all_formulas.py +0 -146
  475. package/skills/vds-skill/vds-scripts/excel_orchestrator/remove_base_multiplier_and_check_duplicates.py +0 -310
  476. package/skills/vds-skill/vds-scripts/excel_orchestrator/remove_duplicate_brd_tasks.py +0 -137
  477. package/skills/vds-skill/vds-scripts/excel_orchestrator/research_based_updates.py +0 -457
  478. package/skills/vds-skill/vds-scripts/excel_orchestrator/restore_e_values.py +0 -172
  479. package/skills/vds-skill/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/__init__.py +0 -5
  480. package/skills/vds-skill/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/cli.py +0 -746
  481. package/skills/vds-skill/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/config.py +0 -74
  482. package/skills/vds-skill/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/converters.py +0 -226
  483. package/skills/vds-skill/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/errors.py +0 -88
  484. package/skills/vds-skill/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/excel_client.py +0 -443
  485. package/skills/vds-skill/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/formatters.py +0 -211
  486. package/skills/vds-skill/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/logging.py +0 -57
  487. package/skills/vds-skill/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/source_contract.py +0 -29
  488. package/skills/vds-skill/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/target_state_status.py +0 -837
  489. package/skills/vds-skill/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/ulnc_alignment.py +0 -1291
  490. package/skills/vds-skill/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/validators.py +0 -164
  491. package/skills/vds-skill/vds-scripts/excel_orchestrator/sync_detail_and_total_sheets.py +0 -211
  492. package/skills/vds-skill/vds-scripts/excel_orchestrator/tests/__init__.py +0 -1
  493. package/skills/vds-skill/vds-scripts/excel_orchestrator/tests/conftest.py +0 -36
  494. package/skills/vds-skill/vds-scripts/excel_orchestrator/tests/test_cli.py +0 -383
  495. package/skills/vds-skill/vds-scripts/excel_orchestrator/tests/test_excel_client.py +0 -129
  496. package/skills/vds-skill/vds-scripts/excel_orchestrator/tests/test_ulnc_alignment.py +0 -373
  497. package/skills/vds-skill/vds-scripts/excel_orchestrator/tests/test_validators.py +0 -64
  498. package/skills/vds-skill/vds-scripts/excel_orchestrator/update_api_database_effort.py +0 -261
  499. package/skills/vds-skill/vds-scripts/excel_orchestrator/update_buffers_inline.py +0 -115
  500. package/skills/vds-skill/vds-scripts/excel_orchestrator/update_complex_services_and_add_new.py +0 -336
  501. package/skills/vds-skill/vds-scripts/excel_orchestrator/update_responsibility_and_fix_rows.py +0 -208
  502. package/skills/vds-skill/vds-scripts/excel_orchestrator/update_task_breakdown_vietnamese.py +0 -309
  503. package/skills/vds-skill/vds-scripts/excel_orchestrator/update_vietnamese_and_responsibility.py +0 -415
  504. package/skills/vds-skill/vds-scripts/excel_orchestrator/verify_brd_coverage_comprehensive.py +0 -401
  505. package/skills/vds-skill/vds-scripts/git_orchestrator/ENHANCEMENT_SUMMARY.md +0 -119
  506. package/skills/vds-skill/vds-scripts/git_orchestrator/README.md +0 -286
  507. package/skills/vds-skill/vds-scripts/git_orchestrator/VERIFICATION_REPORT.md +0 -152
  508. package/skills/vds-skill/vds-scripts/git_orchestrator/pyproject.toml +0 -37
  509. package/skills/vds-skill/vds-scripts/git_orchestrator/src/vds_git_orchestrator/__init__.py +0 -30
  510. package/skills/vds-skill/vds-scripts/git_orchestrator/src/vds_git_orchestrator/__main__.py +0 -4
  511. package/skills/vds-skill/vds-scripts/git_orchestrator/src/vds_git_orchestrator/branch_probe.py +0 -271
  512. package/skills/vds-skill/vds-scripts/git_orchestrator/src/vds_git_orchestrator/cli.py +0 -892
  513. package/skills/vds-skill/vds-scripts/git_orchestrator/src/vds_git_orchestrator/logging_config.py +0 -63
  514. package/skills/vds-skill/vds-scripts/git_orchestrator/src/vds_git_orchestrator/manifest.py +0 -249
  515. package/skills/vds-skill/vds-scripts/git_orchestrator/src/vds_git_orchestrator/orchestrator.py +0 -1647
  516. package/skills/vds-skill/vds-scripts/git_orchestrator/src/vds_git_orchestrator/protocols.py +0 -35
  517. package/skills/vds-skill/vds-scripts/git_orchestrator/src/vds_git_orchestrator/reporting.py +0 -55
  518. package/skills/vds-skill/vds-scripts/git_orchestrator/tests/__init__.py +0 -0
  519. package/skills/vds-skill/vds-scripts/git_orchestrator/tests/test_cli_settings.py +0 -19
  520. package/skills/vds-skill/vds-scripts/git_orchestrator/tests/test_integration.py +0 -79
  521. package/skills/vds-skill/vds-scripts/git_orchestrator/tests/test_manifest.py +0 -79
  522. package/skills/vds-skill/vds-scripts/git_orchestrator/tests/test_orchestrator.py +0 -207
  523. package/skills/vds-skill/vds-scripts/git_orchestrator/tests/test_public_api.py +0 -235
  524. package/skills/vds-skill/vds-scripts/git_orchestrator/tests/test_resilience.py +0 -343
  525. package/skills/vds-skill/vds-scripts/git_orchestrator/tests/unit/__init__.py +0 -0
  526. package/skills/vds-skill/vds-scripts/git_orchestrator/tests/unit/test_branch_probe.py +0 -327
  527. package/skills/vds-skill/vds-scripts/git_orchestrator/tests/unit/test_protocols.py +0 -132
  528. package/skills/vds-skill/vds-scripts/google_sheets_orchestrator/README.md +0 -241
  529. package/skills/vds-skill/vds-scripts/google_sheets_orchestrator/pyproject.toml +0 -45
  530. package/skills/vds-skill/vds-scripts/google_sheets_orchestrator/src/vds_google_sheets_orchestrator/__init__.py +0 -69
  531. package/skills/vds-skill/vds-scripts/google_sheets_orchestrator/src/vds_google_sheets_orchestrator/cli.py +0 -568
  532. package/skills/vds-skill/vds-scripts/google_sheets_orchestrator/src/vds_google_sheets_orchestrator/client.py +0 -186
  533. package/skills/vds-skill/vds-scripts/google_sheets_orchestrator/src/vds_google_sheets_orchestrator/config.py +0 -46
  534. package/skills/vds-skill/vds-scripts/google_sheets_orchestrator/src/vds_google_sheets_orchestrator/errors.py +0 -41
  535. package/skills/vds-skill/vds-scripts/google_sheets_orchestrator/tests/__init__.py +0 -1
  536. package/skills/vds-skill/vds-scripts/google_sheets_orchestrator/tests/conftest.py +0 -1
  537. package/skills/vds-skill/vds-scripts/google_sheets_orchestrator/tests/unit/__init__.py +0 -1
  538. package/skills/vds-skill/vds-scripts/google_sheets_orchestrator/tests/unit/test_cli.py +0 -212
  539. package/skills/vds-skill/vds-scripts/google_sheets_orchestrator/tests/unit/test_client.py +0 -24
  540. package/skills/vds-skill/vds-scripts/google_sheets_orchestrator/tests/unit/test_config.py +0 -16
  541. package/skills/vds-skill/vds-scripts/grafana_orchestrator/README.md +0 -572
  542. package/skills/vds-skill/vds-scripts/grafana_orchestrator/pyproject.toml +0 -102
  543. package/skills/vds-skill/vds-scripts/grafana_orchestrator/src/vds_grafana_orchestrator/__init__.py +0 -78
  544. package/skills/vds-skill/vds-scripts/grafana_orchestrator/src/vds_grafana_orchestrator/cli.py +0 -455
  545. package/skills/vds-skill/vds-scripts/grafana_orchestrator/src/vds_grafana_orchestrator/client.py +0 -700
  546. package/skills/vds-skill/vds-scripts/grafana_orchestrator/src/vds_grafana_orchestrator/config.py +0 -243
  547. package/skills/vds-skill/vds-scripts/grafana_orchestrator/src/vds_grafana_orchestrator/errors.py +0 -34
  548. package/skills/vds-skill/vds-scripts/grafana_orchestrator/src/vds_grafana_orchestrator/py.typed +0 -1
  549. package/skills/vds-skill/vds-scripts/grafana_orchestrator/tests/__init__.py +0 -1
  550. package/skills/vds-skill/vds-scripts/grafana_orchestrator/tests/conftest.py +0 -308
  551. package/skills/vds-skill/vds-scripts/grafana_orchestrator/tests/test_client.py +0 -458
  552. package/skills/vds-skill/vds-scripts/grafana_orchestrator/tests/test_config.py +0 -203
  553. package/skills/vds-skill/vds-scripts/grafana_orchestrator/tests/test_errors.py +0 -78
  554. package/skills/vds-skill/vds-scripts/jira_orchestrator/README.md +0 -864
  555. package/skills/vds-skill/vds-scripts/jira_orchestrator/pyproject.toml +0 -43
  556. package/skills/vds-skill/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/__init__.py +0 -65
  557. package/skills/vds-skill/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/adapter.py +0 -1685
  558. package/skills/vds-skill/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/cli.py +0 -2806
  559. package/skills/vds-skill/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/config.py +0 -168
  560. package/skills/vds-skill/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/errors.py +0 -34
  561. package/skills/vds-skill/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/reporting.py +0 -66
  562. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/__init__.py +0 -1
  563. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/conftest.py +0 -86
  564. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_adapter_agile_list_payloads.py +0 -54
  565. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_adapter_bulk_operations.py +0 -91
  566. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_adapter_components.py +0 -56
  567. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_adapter_createmeta.py +0 -45
  568. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_adapter_dashboard.py +0 -119
  569. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_adapter_issue_properties.py +0 -53
  570. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_adapter_permissions_compat.py +0 -41
  571. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_adapter_reindex.py +0 -42
  572. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_adapter_remote_links.py +0 -75
  573. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_adapter_transitions.py +0 -90
  574. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_adapter_user_management.py +0 -116
  575. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_adapter_version_management.py +0 -181
  576. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_adapter_watchers.py +0 -43
  577. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_advanced_search.py +0 -179
  578. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_agile.py +0 -304
  579. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_application_properties.py +0 -243
  580. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_backlog.py +0 -91
  581. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_bulk_operations.py +0 -403
  582. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_cli.py +0 -108
  583. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_components.py +0 -119
  584. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_config.py +0 -166
  585. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_dashboard.py +0 -122
  586. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_discover_fields.py +0 -207
  587. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_errors.py +0 -72
  588. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_filter_management.py +0 -411
  589. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_issue_archiving.py +0 -179
  590. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_issue_links.py +0 -257
  591. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_issue_properties.py +0 -189
  592. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_link_types.py +0 -407
  593. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_parse_set.py +0 -37
  594. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_permissions.py +0 -343
  595. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_reindex.py +0 -81
  596. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_remote_links.py +0 -269
  597. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_security_schemes.py +0 -202
  598. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_transitions_changelog.py +0 -109
  599. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_user_management.py +0 -246
  600. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_version_management.py +0 -503
  601. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_watchers.py +0 -116
  602. package/skills/vds-skill/vds-scripts/jira_orchestrator/tests/test_worklog.py +0 -243
  603. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/README.md +0 -864
  604. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/pyproject.toml +0 -43
  605. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/src/vds_jira_viettelmoney_orchestrator/__init__.py +0 -65
  606. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/src/vds_jira_viettelmoney_orchestrator/adapter.py +0 -1689
  607. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/src/vds_jira_viettelmoney_orchestrator/cli.py +0 -2799
  608. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/src/vds_jira_viettelmoney_orchestrator/config.py +0 -137
  609. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/src/vds_jira_viettelmoney_orchestrator/errors.py +0 -34
  610. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/src/vds_jira_viettelmoney_orchestrator/reporting.py +0 -65
  611. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/__init__.py +0 -1
  612. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/conftest.py +0 -86
  613. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_adapter_agile_list_payloads.py +0 -54
  614. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_adapter_bulk_operations.py +0 -101
  615. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_adapter_components.py +0 -64
  616. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_adapter_createmeta.py +0 -45
  617. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_adapter_dashboard.py +0 -135
  618. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_adapter_issue_properties.py +0 -63
  619. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_adapter_permissions_compat.py +0 -42
  620. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_adapter_reindex.py +0 -42
  621. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_adapter_remote_links.py +0 -89
  622. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_adapter_transitions.py +0 -91
  623. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_adapter_user_management.py +0 -130
  624. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_adapter_version_management.py +0 -189
  625. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_adapter_watchers.py +0 -49
  626. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_advanced_search.py +0 -213
  627. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_agile.py +0 -334
  628. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_application_properties.py +0 -261
  629. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_backlog.py +0 -91
  630. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_bulk_operations.py +0 -443
  631. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_cli.py +0 -106
  632. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_components.py +0 -133
  633. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_config.py +0 -166
  634. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_dashboard.py +0 -130
  635. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_discover_fields.py +0 -207
  636. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_errors.py +0 -61
  637. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_filter_management.py +0 -478
  638. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_issue_archiving.py +0 -181
  639. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_issue_links.py +0 -257
  640. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_issue_properties.py +0 -203
  641. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_link_types.py +0 -426
  642. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_parse_set.py +0 -37
  643. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_permissions.py +0 -358
  644. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_reindex.py +0 -81
  645. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_remote_links.py +0 -292
  646. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_security_schemes.py +0 -218
  647. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_transitions_changelog.py +0 -121
  648. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_user_management.py +0 -283
  649. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_version_management.py +0 -561
  650. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_watchers.py +0 -128
  651. package/skills/vds-skill/vds-scripts/jira_viettelmoney_orchestrator/tests/test_worklog.py +0 -265
  652. package/skills/vds-skill/vds-scripts/llms.txt +0 -159
  653. package/skills/vds-skill/vds-scripts/markdown_orchestrator/README.md +0 -72
  654. package/skills/vds-skill/vds-scripts/markdown_orchestrator/pyproject.toml +0 -39
  655. package/skills/vds-skill/vds-scripts/markdown_orchestrator/src/vds_markdown_orchestrator/__init__.py +0 -5
  656. package/skills/vds-skill/vds-scripts/markdown_orchestrator/src/vds_markdown_orchestrator/cli.py +0 -102
  657. package/skills/vds-skill/vds-scripts/mcp_server/Dockerfile +0 -63
  658. package/skills/vds-skill/vds-scripts/mcp_server/README.md +0 -140
  659. package/skills/vds-skill/vds-scripts/mcp_server/pyproject.toml +0 -41
  660. package/skills/vds-skill/vds-scripts/mcp_server/src/vds_mcp_server/__init__.py +0 -3
  661. package/skills/vds-skill/vds-scripts/mcp_server/src/vds_mcp_server/config.py +0 -36
  662. package/skills/vds-skill/vds-scripts/mcp_server/src/vds_mcp_server/server.py +0 -111
  663. package/skills/vds-skill/vds-scripts/mcp_server/src/vds_mcp_server/tools/__init__.py +0 -15
  664. package/skills/vds-skill/vds-scripts/mcp_server/src/vds_mcp_server/tools/bitbucket_tools.py +0 -47
  665. package/skills/vds-skill/vds-scripts/mcp_server/src/vds_mcp_server/tools/confluence_tools.py +0 -53
  666. package/skills/vds-skill/vds-scripts/mcp_server/src/vds_mcp_server/tools/git_tools.py +0 -71
  667. package/skills/vds-skill/vds-scripts/mcp_server/src/vds_mcp_server/tools/jira_tools.py +0 -63
  668. package/skills/vds-skill/vds-scripts/mcp_server/src/vds_mcp_server/tools/vidp_tools.py +0 -64
  669. package/skills/vds-skill/vds-scripts/mcp_server/tests/__init__.py +0 -1
  670. package/skills/vds-skill/vds-scripts/mcp_server/tests/conftest.py +0 -31
  671. package/skills/vds-skill/vds-scripts/mcp_server/tests/unit/__init__.py +0 -1
  672. package/skills/vds-skill/vds-scripts/mcp_server/tests/unit/test_bitbucket_tools.py +0 -28
  673. package/skills/vds-skill/vds-scripts/mcp_server/tests/unit/test_confluence_tools.py +0 -28
  674. package/skills/vds-skill/vds-scripts/mcp_server/tests/unit/test_git_tools.py +0 -35
  675. package/skills/vds-skill/vds-scripts/mcp_server/tests/unit/test_jira_tools.py +0 -35
  676. package/skills/vds-skill/vds-scripts/mcp_server/tests/verification/__init__.py +0 -6
  677. package/skills/vds-skill/vds-scripts/mcp_server/tests/verification/conftest.py +0 -51
  678. package/skills/vds-skill/vds-scripts/mcp_server/tests/verification/test_mcp_confluence_tools.py +0 -40
  679. package/skills/vds-skill/vds-scripts/mcp_server/tests/verification/test_mcp_jira_tools.py +0 -39
  680. package/skills/vds-skill/vds-scripts/mcp_server/tests/verification/test_mcp_tool_registration.py +0 -50
  681. package/skills/vds-skill/vds-scripts/pdf_orchestrator/.dockerignore +0 -93
  682. package/skills/vds-skill/vds-scripts/pdf_orchestrator/.env.example +0 -40
  683. package/skills/vds-skill/vds-scripts/pdf_orchestrator/.ruff_rules.py +0 -350
  684. package/skills/vds-skill/vds-scripts/pdf_orchestrator/.yamllint.yml +0 -43
  685. package/skills/vds-skill/vds-scripts/pdf_orchestrator/DEVELOPMENT_PLAN.md +0 -80
  686. package/skills/vds-skill/vds-scripts/pdf_orchestrator/Dockerfile +0 -87
  687. package/skills/vds-skill/vds-scripts/pdf_orchestrator/README.md +0 -608
  688. package/skills/vds-skill/vds-scripts/pdf_orchestrator/cli_verification_test/test.md +0 -6
  689. package/skills/vds-skill/vds-scripts/pdf_orchestrator/cli_verification_test/test.pdf +0 -0
  690. package/skills/vds-skill/vds-scripts/pdf_orchestrator/config/alertmanager.yml +0 -83
  691. package/skills/vds-skill/vds-scripts/pdf_orchestrator/config/prometheus.prod.yml +0 -98
  692. package/skills/vds-skill/vds-scripts/pdf_orchestrator/config/prometheus.yml +0 -40
  693. package/skills/vds-skill/vds-scripts/pdf_orchestrator/config/redis.conf +0 -78
  694. package/skills/vds-skill/vds-scripts/pdf_orchestrator/docs/COMPETITIVE_ANALYSIS_REPORT.md +0 -309
  695. package/skills/vds-skill/vds-scripts/pdf_orchestrator/docs/FEATURES_GUIDE.md +0 -518
  696. package/skills/vds-skill/vds-scripts/pdf_orchestrator/docs/MULTI_USER_DEPLOYMENT_GUIDE.md +0 -615
  697. package/skills/vds-skill/vds-scripts/pdf_orchestrator/docs/USER_GUIDE.md +0 -829
  698. package/skills/vds-skill/vds-scripts/pdf_orchestrator/pyproject.toml +0 -87
  699. package/skills/vds-skill/vds-scripts/pdf_orchestrator/pytest.ini +0 -71
  700. package/skills/vds-skill/vds-scripts/pdf_orchestrator/ruff.toml +0 -6
  701. package/skills/vds-skill/vds-scripts/pdf_orchestrator/scripts/debug_security_report.py +0 -59
  702. package/skills/vds-skill/vds-scripts/pdf_orchestrator/scripts/demo_library_selector.py +0 -109
  703. package/skills/vds-skill/vds-scripts/pdf_orchestrator/scripts/generate_project_stats.py +0 -52
  704. package/skills/vds-skill/vds-scripts/pdf_orchestrator/scripts/generate_styled_pdf.py +0 -95
  705. package/skills/vds-skill/vds-scripts/pdf_orchestrator/scripts/migrate_render_pdfs.py +0 -285
  706. package/skills/vds-skill/vds-scripts/pdf_orchestrator/scripts/setup_team.bat +0 -283
  707. package/skills/vds-skill/vds-scripts/pdf_orchestrator/scripts/setup_team.sh +0 -324
  708. package/skills/vds-skill/vds-scripts/pdf_orchestrator/src/vds_pdf_orchestrator/__init__.py +0 -5
  709. package/skills/vds-skill/vds-scripts/pdf_orchestrator/src/vds_pdf_orchestrator/cli.py +0 -542
  710. package/skills/vds-skill/vds-scripts/pdf_orchestrator/src/vds_pdf_orchestrator/config.py +0 -33
  711. package/skills/vds-skill/vds-scripts/pdf_orchestrator/tests/README.md +0 -650
  712. package/skills/vds-skill/vds-scripts/pdf_orchestrator/tests/__init__.py +0 -0
  713. package/skills/vds-skill/vds-scripts/pdf_orchestrator/tests/conftest.py +0 -520
  714. package/skills/vds-skill/vds-scripts/pdf_orchestrator/tests/requirements.txt +0 -51
  715. package/skills/vds-skill/vds-scripts/pdf_orchestrator/tests/run_tests.py +0 -659
  716. package/skills/vds-skill/vds-scripts/pdf_orchestrator/tests/test_config.py +0 -36
  717. package/skills/vds-skill/vds-scripts/platform_core/pyproject.toml +0 -49
  718. package/skills/vds-skill/vds-scripts/platform_core/src/vds_platform_core/__init__.py +0 -16
  719. package/skills/vds-skill/vds-scripts/platform_core/src/vds_platform_core/alembic/__init__.py +0 -18
  720. package/skills/vds-skill/vds-scripts/platform_core/src/vds_platform_core/alembic/runtime.py +0 -139
  721. package/skills/vds-skill/vds-scripts/platform_core/src/vds_platform_core/config.py +0 -88
  722. package/skills/vds-skill/vds-scripts/platform_core/src/vds_platform_core/credentials.py +0 -40
  723. package/skills/vds-skill/vds-scripts/platform_core/src/vds_platform_core/env.py +0 -24
  724. package/skills/vds-skill/vds-scripts/platform_core/src/vds_platform_core/errors.py +0 -127
  725. package/skills/vds-skill/vds-scripts/platform_core/src/vds_platform_core/http/__init__.py +0 -18
  726. package/skills/vds-skill/vds-scripts/platform_core/src/vds_platform_core/http/auth.py +0 -32
  727. package/skills/vds-skill/vds-scripts/platform_core/src/vds_platform_core/http/errors.py +0 -47
  728. package/skills/vds-skill/vds-scripts/platform_core/src/vds_platform_core/http/pagination.py +0 -65
  729. package/skills/vds-skill/vds-scripts/platform_core/src/vds_platform_core/http/retry.py +0 -62
  730. package/skills/vds-skill/vds-scripts/platform_core/src/vds_platform_core/http/stack.py +0 -61
  731. package/skills/vds-skill/vds-scripts/platform_core/src/vds_platform_core/logging.py +0 -132
  732. package/skills/vds-skill/vds-scripts/platform_core/src/vds_platform_core/protocols.py +0 -77
  733. package/skills/vds-skill/vds-scripts/platform_core/src/vds_platform_core/serialization.py +0 -80
  734. package/skills/vds-skill/vds-scripts/platform_core/src/vds_platform_core/severity.py +0 -175
  735. package/skills/vds-skill/vds-scripts/platform_core/tests/__init__.py +0 -0
  736. package/skills/vds-skill/vds-scripts/platform_core/tests/conftest.py +0 -1
  737. package/skills/vds-skill/vds-scripts/platform_core/tests/test_alembic_runtime.py +0 -300
  738. package/skills/vds-skill/vds-scripts/platform_core/tests/test_auth.py +0 -84
  739. package/skills/vds-skill/vds-scripts/platform_core/tests/test_config.py +0 -83
  740. package/skills/vds-skill/vds-scripts/platform_core/tests/test_credentials.py +0 -73
  741. package/skills/vds-skill/vds-scripts/platform_core/tests/test_env.py +0 -56
  742. package/skills/vds-skill/vds-scripts/platform_core/tests/test_errors.py +0 -201
  743. package/skills/vds-skill/vds-scripts/platform_core/tests/test_errors_http.py +0 -74
  744. package/skills/vds-skill/vds-scripts/platform_core/tests/test_http_settings.py +0 -116
  745. package/skills/vds-skill/vds-scripts/platform_core/tests/test_logging.py +0 -148
  746. package/skills/vds-skill/vds-scripts/platform_core/tests/test_pagination.py +0 -153
  747. package/skills/vds-skill/vds-scripts/platform_core/tests/test_protocols.py +0 -132
  748. package/skills/vds-skill/vds-scripts/platform_core/tests/test_retry.py +0 -151
  749. package/skills/vds-skill/vds-scripts/platform_core/tests/test_serialization.py +0 -92
  750. package/skills/vds-skill/vds-scripts/platform_core/tests/test_severity.py +0 -178
  751. package/skills/vds-skill/vds-scripts/platform_core/tests/test_stack.py +0 -130
  752. package/skills/vds-skill/vds-scripts/platform_core/uv.lock +0 -341
  753. package/skills/vds-skill/vds-scripts/pyproject.toml +0 -145
  754. package/skills/vds-skill/vds-scripts/pyrightconfig.json +0 -82
  755. package/skills/vds-skill/vds-scripts/repo-manifest.yaml +0 -380
  756. package/skills/vds-skill/vds-scripts/repo-manifest.yaml.example +0 -25
  757. package/skills/vds-skill/vds-scripts/ruff.toml +0 -100
  758. package/skills/vds-skill/vds-scripts/scripts/BRD-Validation-API.postman_collection.json +0 -706
  759. package/skills/vds-skill/vds-scripts/scripts/BRD-Validation-README.md +0 -308
  760. package/skills/vds-skill/vds-scripts/scripts/README.md +0 -271
  761. package/skills/vds-skill/vds-scripts/scripts/_validate_alias_phase2.py +0 -137
  762. package/skills/vds-skill/vds-scripts/scripts/audit-cli-patterns.sh +0 -135
  763. package/skills/vds-skill/vds-scripts/scripts/audit-dashboard.sh +0 -525
  764. package/skills/vds-skill/vds-scripts/scripts/backup.sh +0 -123
  765. package/skills/vds-skill/vds-scripts/scripts/bootstrap_uv.sh +0 -69
  766. package/skills/vds-skill/vds-scripts/scripts/brd-validation-environment.json +0 -51
  767. package/skills/vds-skill/vds-scripts/scripts/brd-validation-test-results.json +0 -13023
  768. package/skills/vds-skill/vds-scripts/scripts/brd_coverage_report.json +0 -276
  769. package/skills/vds-skill/vds-scripts/scripts/check-future-annotations.py +0 -22
  770. package/skills/vds-skill/vds-scripts/scripts/check-invalid-symlinks.py +0 -183
  771. package/skills/vds-skill/vds-scripts/scripts/check-no-debug-markers.py +0 -21
  772. package/skills/vds-skill/vds-scripts/scripts/check-no-unittest.py +0 -21
  773. package/skills/vds-skill/vds-scripts/scripts/ci/assert_no_openspace_commits.sh +0 -37
  774. package/skills/vds-skill/vds-scripts/scripts/ci/verify_branch_protection.sh +0 -64
  775. package/skills/vds-skill/vds-scripts/scripts/closure/phase1_check.sh +0 -483
  776. package/skills/vds-skill/vds-scripts/scripts/closure/phase2_check.sh +0 -500
  777. package/skills/vds-skill/vds-scripts/scripts/create_memory_session.py +0 -36
  778. package/skills/vds-skill/vds-scripts/scripts/deploy-bootstrap.sh +0 -201
  779. package/skills/vds-skill/vds-scripts/scripts/deployment/load_docker_images_offline.sh +0 -90
  780. package/skills/vds-skill/vds-scripts/scripts/dev/cli_smoke.sh +0 -259
  781. package/skills/vds-skill/vds-scripts/scripts/final_completion_report.md +0 -139
  782. package/skills/vds-skill/vds-scripts/scripts/folder_structure_report.json +0 -321
  783. package/skills/vds-skill/vds-scripts/scripts/generate_completion_report.py +0 -132
  784. package/skills/vds-skill/vds-scripts/scripts/generate_intellij_modules.py +0 -154
  785. package/skills/vds-skill/vds-scripts/scripts/init-pgbouncer-userlist.sh +0 -154
  786. package/skills/vds-skill/vds-scripts/scripts/link_integrity_report.json +0 -807
  787. package/skills/vds-skill/vds-scripts/scripts/move_audit_artifact_pages.py +0 -252
  788. package/skills/vds-skill/vds-scripts/scripts/move_audit_artifact_pages_rest.py +0 -165
  789. package/skills/vds-skill/vds-scripts/scripts/move_wrong_dept_pages.py +0 -235
  790. package/skills/vds-skill/vds-scripts/scripts/openspace_bootstrap.sh +0 -56
  791. package/skills/vds-skill/vds-scripts/scripts/openspace_common.sh +0 -75
  792. package/skills/vds-skill/vds-scripts/scripts/openspace_doctor.sh +0 -61
  793. package/skills/vds-skill/vds-scripts/scripts/openspace_sync_shadow.sh +0 -65
  794. package/skills/vds-skill/vds-scripts/scripts/phase7-baseline.sh +0 -77
  795. package/skills/vds-skill/vds-scripts/scripts/preflight/env_check.sh +0 -102
  796. package/skills/vds-skill/vds-scripts/scripts/repair_autopay_reports.sh +0 -173
  797. package/skills/vds-skill/vds-scripts/scripts/rollback_drill.sh +0 -659
  798. package/skills/vds-skill/vds-scripts/scripts/run-audit-in-tmux.sh +0 -286
  799. package/skills/vds-skill/vds-scripts/scripts/run-department-audit.sh +0 -495
  800. package/skills/vds-skill/vds-scripts/scripts/run-project-audit.sh +0 -267
  801. package/skills/vds-skill/vds-scripts/scripts/save_intellij_memories.py +0 -112
  802. package/skills/vds-skill/vds-scripts/scripts/save_memories_to_vds_ai.py +0 -81
  803. package/skills/vds-skill/vds-scripts/scripts/save_memories_vds_style.py +0 -133
  804. package/skills/vds-skill/vds-scripts/scripts/search_intellij_memories.py +0 -48
  805. package/skills/vds-skill/vds-scripts/scripts/setup_intellij_workspace.py +0 -71
  806. package/skills/vds-skill/vds-scripts/scripts/smoke-test-deploy.sh +0 -137
  807. package/skills/vds-skill/vds-scripts/scripts/smoke_deploy_lib.py +0 -205
  808. package/skills/vds-skill/vds-scripts/scripts/target-state-automation/README.md +0 -89
  809. package/skills/vds-skill/vds-scripts/scripts/target-state-automation/confluence_sync_coordinator.sh +0 -27
  810. package/skills/vds-skill/vds-scripts/scripts/target-state-automation/coordination.sh +0 -114
  811. package/skills/vds-skill/vds-scripts/scripts/target-state-automation/diagram_coordinator.sh +0 -25
  812. package/skills/vds-skill/vds-scripts/scripts/target-state-automation/docs_root.sh +0 -22
  813. package/skills/vds-skill/vds-scripts/scripts/target-state-automation/generate_diagrams.sh +0 -22
  814. package/skills/vds-skill/vds-scripts/scripts/target-state-automation/markdown_coordinator.sh +0 -25
  815. package/skills/vds-skill/vds-scripts/scripts/target-state-automation/progress_dashboard.sh +0 -17
  816. package/skills/vds-skill/vds-scripts/scripts/target-state-automation/schema_coordinator.sh +0 -25
  817. package/skills/vds-skill/vds-scripts/scripts/target-state-automation/sync_confluence.sh +0 -30
  818. package/skills/vds-skill/vds-scripts/scripts/target-state-automation/update_dependencies.sh +0 -19
  819. package/skills/vds-skill/vds-scripts/scripts/target-state-automation/validate_links.sh +0 -86
  820. package/skills/vds-skill/vds-scripts/scripts/target-state-automation/validate_markdown.sh +0 -52
  821. package/skills/vds-skill/vds-scripts/scripts/target-state-automation/validate_schemas.sh +0 -26
  822. package/skills/vds-skill/vds-scripts/scripts/target-state-automation/validate_structure.sh +0 -98
  823. package/skills/vds-skill/vds-scripts/scripts/tests/__init__.py +0 -1
  824. package/skills/vds-skill/vds-scripts/scripts/tests/test_dockerfile_correctness.py +0 -815
  825. package/skills/vds-skill/vds-scripts/scripts/tests/test_makefile_loadouts.py +0 -560
  826. package/skills/vds-skill/vds-scripts/scripts/tests/test_smoke_deploy.py +0 -313
  827. package/skills/vds-skill/vds-scripts/scripts/tests/test_verify_alembic.py +0 -581
  828. package/skills/vds-skill/vds-scripts/scripts/tests/test_verify_infra_topology.py +0 -254
  829. package/skills/vds-skill/vds-scripts/scripts/update_modules_xml.py +0 -194
  830. package/skills/vds-skill/vds-scripts/scripts/uv-workspace-alignment-verification-2026-03-25.md +0 -128
  831. package/skills/vds-skill/vds-scripts/scripts/uv-workspace-alignment-verification-2026-04-18.md +0 -100
  832. package/skills/vds-skill/vds-scripts/scripts/validate-cli-standardization.sh +0 -188
  833. package/skills/vds-skill/vds-scripts/scripts/validate_brd_coverage.py +0 -197
  834. package/skills/vds-skill/vds-scripts/scripts/validate_folder_structure.py +0 -234
  835. package/skills/vds-skill/vds-scripts/scripts/validate_link_integrity.py +0 -274
  836. package/skills/vds-skill/vds-scripts/scripts/vami017-caller-compat-report.md +0 -62
  837. package/skills/vds-skill/vds-scripts/scripts/vami017-phase-b-scaffold-notes.md +0 -79
  838. package/skills/vds-skill/vds-scripts/scripts/vds_sh_helpers.sh +0 -180
  839. package/skills/vds-skill/vds-scripts/scripts/verification/phase2_portable_paths_ubuntu_docker.sh +0 -26
  840. package/skills/vds-skill/vds-scripts/scripts/verify-infra-topology.py +0 -868
  841. package/skills/vds-skill/vds-scripts/scripts/verify-memory-cli-e2e.sh +0 -598
  842. package/skills/vds-skill/vds-scripts/scripts/verify-worktree-features.sh +0 -306
  843. package/skills/vds-skill/vds-scripts/scripts/worktree-add.sh +0 -128
  844. package/skills/vds-skill/vds-scripts/scripts/worktree-remove.sh +0 -112
  845. package/skills/vds-skill/vds-scripts/scripts/worktree_compose.sh +0 -269
  846. package/skills/vds-skill/vds-scripts/scripts/worktree_uv.sh +0 -77
  847. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/IMPLEMENTATION_AUDIT.md +0 -376
  848. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/README.md +0 -507
  849. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/pyproject.toml +0 -106
  850. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/scripts/ensure_symlink.sh +0 -38
  851. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/src/vds_sonarqube_orchestrator/__init__.py +0 -164
  852. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/src/vds_sonarqube_orchestrator/batch.py +0 -212
  853. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/src/vds_sonarqube_orchestrator/cli.py +0 -1407
  854. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/src/vds_sonarqube_orchestrator/client.py +0 -608
  855. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/src/vds_sonarqube_orchestrator/config.py +0 -260
  856. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/src/vds_sonarqube_orchestrator/diff.py +0 -220
  857. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/src/vds_sonarqube_orchestrator/errors.py +0 -34
  858. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/src/vds_sonarqube_orchestrator/external_sca.py +0 -932
  859. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/src/vds_sonarqube_orchestrator/portfolio.py +0 -225
  860. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/src/vds_sonarqube_orchestrator/pr.py +0 -505
  861. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/src/vds_sonarqube_orchestrator/reports.py +0 -342
  862. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/src/vds_sonarqube_orchestrator/scanner.py +0 -351
  863. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/src/vds_sonarqube_orchestrator/webhooks.py +0 -269
  864. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/tests/__init__.py +0 -0
  865. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/tests/conftest.py +0 -134
  866. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/tests/test_batch.py +0 -419
  867. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/tests/test_config.py +0 -145
  868. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/tests/test_errors.py +0 -78
  869. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/tests/test_external_sca.py +0 -466
  870. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/tests/test_pr.py +0 -471
  871. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/tests/test_reports.py +0 -511
  872. package/skills/vds-skill/vds-scripts/sonarqube_orchestrator/tests/test_webhooks.py +0 -660
  873. package/skills/vds-skill/vds-scripts/uv.lock +0 -5046
  874. package/skills/vds-skill/vds-scripts/vds_agent_core/CHANGELOG.md +0 -36
  875. package/skills/vds-skill/vds-scripts/vds_agent_core/README.md +0 -453
  876. package/skills/vds-skill/vds-scripts/vds_agent_core/docs/PHASE9A_ASSESSMENT.md +0 -50
  877. package/skills/vds-skill/vds-scripts/vds_agent_core/docs/embedding.md +0 -468
  878. package/skills/vds-skill/vds-scripts/vds_agent_core/pyproject.toml +0 -51
  879. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/__init__.py +0 -29
  880. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/agents/__init__.py +0 -26
  881. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/agents/hooks.py +0 -119
  882. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/agents/loop.py +0 -864
  883. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/agents/tools.py +0 -41
  884. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/config.py +0 -252
  885. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/llm/__init__.py +0 -55
  886. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/llm/_cascade.py +0 -143
  887. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/llm/budget.py +0 -353
  888. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/llm/cache.py +0 -373
  889. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/llm/embedding.py +0 -815
  890. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/llm/provider.py +0 -173
  891. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/llm/schemas.py +0 -45
  892. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/observability/__init__.py +0 -77
  893. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/observability/decorators.py +0 -258
  894. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/observability/jsonl_exporter.py +0 -236
  895. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/observability/tracer.py +0 -497
  896. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/profiles.py +0 -2015
  897. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/runtime/__init__.py +0 -0
  898. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/runtime/agent_id.py +0 -60
  899. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/security/__init__.py +0 -13
  900. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/security/credentials.py +0 -106
  901. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/skills/__init__.py +0 -1
  902. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/skills/executor.py +0 -238
  903. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/skills/manager.py +0 -381
  904. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/skills/policy.py +0 -568
  905. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/workflows/__init__.py +0 -19
  906. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/workflows/langgraph_runner.py +0 -102
  907. package/skills/vds-skill/vds-scripts/vds_agent_core/src/vds_agent_core/workflows/protocols.py +0 -81
  908. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/__init__.py +0 -0
  909. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/conftest.py +0 -62
  910. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/integration/__init__.py +0 -0
  911. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/integration/test_audit_loop_hooks_integration.py +0 -135
  912. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/integration/test_audit_observability_integration.py +0 -246
  913. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/integration/test_public_api_stability.py +0 -91
  914. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/__init__.py +0 -0
  915. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/llm/__init__.py +0 -0
  916. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/llm/test_call_site_parallelism.py +0 -30
  917. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/llm/test_dimension_guardrail.py +0 -25
  918. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/llm/test_drop_in_provider_extensibility.py +0 -76
  919. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/llm/test_embedding.py +0 -393
  920. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/llm/test_embedding_cache.py +0 -302
  921. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/llm/test_embedding_extra.py +0 -696
  922. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/llm/test_embedding_subclass.py +0 -49
  923. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/llm/test_no_provider_leakage_in_env.py +0 -34
  924. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/llm/test_provider_auto_route.py +0 -48
  925. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/llm/test_runtime_log_clean.py +0 -111
  926. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/llm/test_w7_logic_fixes.py +0 -219
  927. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/profiles/__init__.py +0 -0
  928. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/profiles/test_embedding_block_parser.py +0 -194
  929. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/profiles/test_env_resolver_allowlist.py +0 -141
  930. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/profiles/test_profile_authorization.py +0 -158
  931. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/profiles/test_profiles_w3_extra.py +0 -547
  932. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/profiles/test_real_audit_profile_compat.py +0 -129
  933. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/runtime/__init__.py +0 -0
  934. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/runtime/test_for_agent.py +0 -322
  935. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/runtime/test_w9_cascade_edges.py +0 -369
  936. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/security/__init__.py +0 -0
  937. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/security/test_credentials.py +0 -132
  938. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_agent_loop.py +0 -663
  939. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_agent_loop_coverage.py +0 -429
  940. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_agents_hooks_defaults.py +0 -22
  941. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_budget.py +0 -155
  942. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_budget_coverage.py +0 -264
  943. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_budget_tracking_only.py +0 -71
  944. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_cache.py +0 -251
  945. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_cache_context.py +0 -62
  946. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_config.py +0 -155
  947. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_langgraph_runner.py +0 -45
  948. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_langgraph_runner_coverage.py +0 -98
  949. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_llm_cache_deep.py +0 -113
  950. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_observability_decorators.py +0 -697
  951. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_observability_hooks.py +0 -217
  952. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_observability_jsonl_exporter.py +0 -542
  953. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_observability_jsonl_wiring.py +0 -313
  954. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_observability_tracer.py +0 -896
  955. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_profiles.py +0 -1571
  956. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_profiles_coverage.py +0 -444
  957. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_provider.py +0 -316
  958. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_schemas.py +0 -63
  959. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_skill_executor.py +0 -297
  960. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_skill_manager.py +0 -370
  961. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_skill_manager_coverage.py +0 -364
  962. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_skill_policy.py +0 -402
  963. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_skill_rubric.py +0 -47
  964. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_tools.py +0 -51
  965. package/skills/vds-skill/vds-scripts/vds_agent_core/tests/unit/test_workflow_protocols.py +0 -136
  966. package/skills/vds-skill/vds-scripts/vds_cli/README.md +0 -201
  967. package/skills/vds-skill/vds-scripts/vds_cli/VERIFICATION_REPORT.md +0 -41
  968. package/skills/vds-skill/vds-scripts/vds_cli/pyproject.toml +0 -50
  969. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/__init__.py +0 -3
  970. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/assets/git-credential-helper.py +0 -235
  971. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/cli.py +0 -1158
  972. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/commands/__init__.py +0 -1
  973. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/commands/lint_cli.py +0 -389
  974. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/confluence_sync.py +0 -846
  975. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/docs/consumption/__init__.py +0 -7
  976. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/docs/consumption/funnel.py +0 -105
  977. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/docs/consumption/scanner.py +0 -211
  978. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/docs/freshness/report.py +0 -90
  979. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/docs/types.py +0 -27
  980. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/docs_cmd.py +0 -672
  981. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/docs_metrics.py +0 -75
  982. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/docs_sync.py +0 -1171
  983. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/ecosystem/__init__.py +0 -39
  984. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/ecosystem/report.py +0 -439
  985. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/ecosystem_docs.py +0 -164
  986. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/env.py +0 -111
  987. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/env_git_helper.py +0 -281
  988. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/google_sheets_orchestrator/__init__.py +0 -3
  989. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/google_sheets_orchestrator/google_sheets_orchestrator.py +0 -173
  990. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/router.py +0 -232
  991. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/skills_cmd.py +0 -274
  992. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/sync_api.py +0 -613
  993. package/skills/vds-skill/vds-scripts/vds_cli/src/vds_cli/sync_service.py +0 -283
  994. package/skills/vds-skill/vds-scripts/vds_cli/tests/conftest.py +0 -62
  995. package/skills/vds-skill/vds-scripts/vds_cli/tests/test_env_git_helper_lifecycle.py +0 -261
  996. package/skills/vds-skill/vds-scripts/vds_cli/tests/test_git_credential_helper.py +0 -240
  997. package/skills/vds-skill/vds-scripts/vds_cli/tests/test_router_help_proxy.py +0 -43
  998. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_cli.py +0 -264
  999. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_cli_DOC004.py +0 -110
  1000. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_confluence_sync.py +0 -315
  1001. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_confluence_sync_wave7.py +0 -375
  1002. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_consumption_funnel.py +0 -106
  1003. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_consumption_scanner.py +0 -144
  1004. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_docs_cmd.py +0 -89
  1005. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_docs_cmd_wave8.py +0 -161
  1006. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_docs_metrics.py +0 -16
  1007. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_docs_quality_score.py +0 -61
  1008. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_docs_sync.py +0 -417
  1009. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_ecosystem_cli_dashboard.py +0 -667
  1010. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_ecosystem_cli_dashboard_rendering.py +0 -143
  1011. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_ecosystem_docs.py +0 -63
  1012. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_env.py +0 -85
  1013. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_freshness_report.py +0 -125
  1014. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_lint_cli.py +0 -224
  1015. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_router.py +0 -101
  1016. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_skills_cmd.py +0 -419
  1017. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_sync_api.py +0 -357
  1018. package/skills/vds-skill/vds-scripts/vds_cli/tests/unit/test_sync_service.py +0 -170
  1019. package/skills/vds-skill/vds-scripts/vds_cli/tests/verification/conftest.py +0 -51
  1020. package/skills/vds-skill/vds-scripts/vds_cli/tests/verification/test_bitbucket_real.py +0 -32
  1021. package/skills/vds-skill/vds-scripts/vds_cli/tests/verification/test_confluence_real.py +0 -32
  1022. package/skills/vds-skill/vds-scripts/vds_cli/tests/verification/test_jira_real.py +0 -40
  1023. package/skills/vds-skill/vds-scripts/vds_cli_common/README.md +0 -190
  1024. package/skills/vds-skill/vds-scripts/vds_cli_common/pyproject.toml +0 -96
  1025. package/skills/vds-skill/vds-scripts/vds_cli_common/src/vds_cli_common/__init__.py +0 -36
  1026. package/skills/vds-skill/vds-scripts/vds_cli_common/src/vds_cli_common/app.py +0 -55
  1027. package/skills/vds-skill/vds-scripts/vds_cli_common/src/vds_cli_common/completers.py +0 -139
  1028. package/skills/vds-skill/vds-scripts/vds_cli_common/src/vds_cli_common/context.py +0 -201
  1029. package/skills/vds-skill/vds-scripts/vds_cli_common/src/vds_cli_common/env.py +0 -163
  1030. package/skills/vds-skill/vds-scripts/vds_cli_common/src/vds_cli_common/errors.py +0 -440
  1031. package/skills/vds-skill/vds-scripts/vds_cli_common/src/vds_cli_common/migrate_sdlc_config.py +0 -210
  1032. package/skills/vds-skill/vds-scripts/vds_cli_common/src/vds_cli_common/output.py +0 -284
  1033. package/skills/vds-skill/vds-scripts/vds_cli_common/src/vds_cli_common/paths.py +0 -78
  1034. package/skills/vds-skill/vds-scripts/vds_cli_common/src/vds_cli_common/testing.py +0 -211
  1035. package/skills/vds-skill/vds-scripts/vds_cli_common/src/vds_cli_common/version.py +0 -85
  1036. package/skills/vds-skill/vds-scripts/vds_cli_common/tests/__init__.py +0 -0
  1037. package/skills/vds-skill/vds-scripts/vds_cli_common/tests/test_app.py +0 -126
  1038. package/skills/vds-skill/vds-scripts/vds_cli_common/tests/test_completers.py +0 -148
  1039. package/skills/vds-skill/vds-scripts/vds_cli_common/tests/test_context.py +0 -192
  1040. package/skills/vds-skill/vds-scripts/vds_cli_common/tests/test_env.py +0 -235
  1041. package/skills/vds-skill/vds-scripts/vds_cli_common/tests/test_errors.py +0 -275
  1042. package/skills/vds-skill/vds-scripts/vds_cli_common/tests/test_migrate_sdlc_config.py +0 -257
  1043. package/skills/vds-skill/vds-scripts/vds_cli_common/tests/test_output.py +0 -229
  1044. package/skills/vds-skill/vds-scripts/vds_cli_common/tests/test_paths.py +0 -61
  1045. package/skills/vds-skill/vds-scripts/vds_cli_common/tests/test_testing.py +0 -138
  1046. package/skills/vds-skill/vds-scripts/vds_cli_common/tests/test_version.py +0 -64
  1047. package/skills/vds-skill/vds-scripts/vidp_orchestrator/README.md +0 -31
  1048. package/skills/vds-skill/vds-scripts/vidp_orchestrator/pyproject.toml +0 -50
  1049. package/skills/vds-skill/vds-scripts/vidp_orchestrator/src/vds_vidp_orchestrator/__init__.py +0 -26
  1050. package/skills/vds-skill/vds-scripts/vidp_orchestrator/src/vds_vidp_orchestrator/cli.py +0 -246
  1051. package/skills/vds-skill/vds-scripts/vidp_orchestrator/src/vds_vidp_orchestrator/client.py +0 -104
  1052. package/skills/vds-skill/vds-scripts/vidp_orchestrator/src/vds_vidp_orchestrator/config.py +0 -82
  1053. package/skills/vds-skill/vds-scripts/vidp_orchestrator/src/vds_vidp_orchestrator/workflows.json +0 -3
  1054. package/skills/vds-skill/vds-scripts/vidp_orchestrator/src/vds_vidp_orchestrator/workflows.py +0 -130
  1055. package/skills/vds-skill/vds-scripts-skill/.openskills.json +0 -6
  1056. package/skills/vds-skill/vds-scripts-skill/QUALITY.md +0 -44
  1057. package/skills/vds-skill/vds-scripts-skill/SKILL.md +0 -132
  1058. package/skills/vds-skill/vds-scripts-skill/references/audit-commands.md +0 -171
  1059. package/skills/vds-skill/vds-scripts-skill/references/capability-index.md +0 -34
  1060. package/skills/vds-skill/vds-scripts-skill/references/development-commands.md +0 -12
  1061. package/skills/vds-skill/vds-scripts-skill/references/google-sheets.md +0 -71
  1062. package/skills/vds-skill/vds-scripts-skill/references/integration-commands.md +0 -17
  1063. package/skills/vds-skill/vds-scripts-skill/references/platform-bootstrap.md +0 -31
  1064. package/skills/vds-skill/vds-scripts-skill/references/specialist-routing.md +0 -14
  1065. package/skills/vds-skill/vds-scripts-skill/references/validation-commands.md +0 -15
@@ -1,3160 +0,0 @@
1
- """Typer CLI wrapper for Confluence operations during the native Python implementations."""
2
-
3
- from __future__ import annotations
4
-
5
- import json
6
- import logging
7
- import os
8
- import sys
9
- from dataclasses import asdict, dataclass
10
- from datetime import UTC, datetime
11
- from pathlib import Path
12
- from typing import Any, cast
13
- from urllib.parse import urlparse
14
-
15
- import structlog
16
- import typer
17
- from vds_platform_core.logging import configure_structlog
18
-
19
- from .config import ConfluenceSettings, load_settings
20
- from .content import ContentClient
21
- from .content_v2 import ContentClientV2
22
- from .crawl_tree import CrawlOptions, crawl_tree_to_disk
23
- from .errors import VDSClientError
24
- from .eventing import Poller
25
- from .http import ConfluenceClient
26
- from .orchestration import BatchRunner, WebhookClient
27
- from .reporting import RunSummary, write_reports
28
- from .tree_copier import CopyOptions, TreeCopier
29
-
30
- # ---------------------------------------------------------------------------
31
- # Typer setup & logging
32
- # ---------------------------------------------------------------------------
33
-
34
- app = typer.Typer(add_completion=False, help="Confluence operations orchestrator")
35
- content_app = typer.Typer(help="Native Confluence API commands")
36
- batch_app = typer.Typer(help="Batch polling utilities (REST v1)")
37
- webhook_app = typer.Typer(help="Webhook management (REST v1)")
38
- app.add_typer(content_app, name="content")
39
- app.add_typer(batch_app, name="batch-native")
40
- app.add_typer(webhook_app, name="webhook-native")
41
-
42
- # Logger will be configured in main() callback
43
- logger = logging.getLogger("confluence_cli")
44
-
45
- # ---------------------------------------------------------------------------
46
- # Paths and legacy script mapping
47
- # ---------------------------------------------------------------------------
48
-
49
- _SCRIPTS_DIR = Path(__file__).resolve().parents[3]
50
- _DEFAULT_REPORT_DIR = (_SCRIPTS_DIR / "reports" / "confluence_runs").resolve()
51
-
52
-
53
- @dataclass(slots=True)
54
- class CLIContext:
55
- report_dir: Path
56
- markdown: bool
57
- api_version: str
58
- reports: bool
59
-
60
-
61
- # ---------------------------------------------------------------------------
62
- # Helper functions
63
- # ---------------------------------------------------------------------------
64
-
65
-
66
- def _normalise_server(server: str | None, settings: ConfluenceSettings) -> str:
67
- return server.lower() if server else settings.default_server.lower()
68
-
69
-
70
- def _infer_server_from_root_ref(root_ref: str, settings: ConfluenceSettings) -> str | None:
71
- root_ref = (root_ref or "").strip()
72
- if not root_ref:
73
- return None
74
-
75
- parsed = urlparse(root_ref)
76
- if not parsed.scheme or not parsed.netloc:
77
- return None
78
-
79
- target = parsed.netloc.lower()
80
- internal = urlparse(str(settings.internal_url)).netloc.lower()
81
- external = urlparse(str(settings.external_url)).netloc.lower()
82
-
83
- if target == internal:
84
- return "internal"
85
- if target == external:
86
- return "external"
87
- return None
88
-
89
-
90
- def _build_env(server: str, settings: ConfluenceSettings) -> dict:
91
- token = settings.token_for(server)
92
- if not token and not (settings.username and settings.password):
93
- raise VDSClientError(
94
- f"Credentials for server '{server}' are missing. Provide VDS_USERNAME+VDS_PASSWORD as the primary auth mechanism or tokens "
95
- "(INTERNAL_CONFLUENCE_TOKEN/EXTERNAL_CONFLUENCE_TOKEN) as fallback.",
96
- context={"server": server},
97
- )
98
- env = os.environ.copy()
99
- env.update(
100
- {
101
- "CONFLUENCE_SERVER": server,
102
- "CONFLUENCE_TOKEN": token or "",
103
- "CONFLUENCE_URL": str(settings.url_for(server)),
104
- "INTERNAL_CONFLUENCE_TOKEN": settings.internal_token or "",
105
- "EXTERNAL_CONFLUENCE_TOKEN": settings.external_token or "",
106
- }
107
- )
108
- return env
109
-
110
-
111
- def _build_http_client(settings: ConfluenceSettings, server: str) -> ConfluenceClient:
112
- return ConfluenceClient(settings, server=server)
113
-
114
-
115
- def _get_cli_ctx(ctx: typer.Context) -> CLIContext:
116
- cli_ctx = ctx.obj
117
- if not isinstance(cli_ctx, CLIContext):
118
- raise RuntimeError("CLI context not initialised")
119
- return cli_ctx
120
-
121
-
122
- def _ensure_v1_api(_ctx: typer.Context, _command: str) -> None:
123
- """Legacy command guard - redirects to native implementations."""
124
- settings = load_settings(strict=False)
125
- if settings is None:
126
- typer.echo("Error: configuration not found", err=True)
127
- raise typer.Exit(code=1) from None
128
-
129
-
130
- def _build_content_client(
131
- settings: ConfluenceSettings,
132
- server: str,
133
- api_version: str,
134
- ):
135
- http_client = _build_http_client(settings, server)
136
- if not http_client.supports_api_version(api_version):
137
- raise VDSClientError(
138
- f"API version '{api_version}' is not supported for server '{server}'.",
139
- context={"server": server, "api_version": api_version},
140
- )
141
- if api_version == "v1":
142
- return ContentClient(http_client)
143
- if api_version == "v2":
144
- return ContentClientV2(http_client)
145
- raise VDSClientError(f"Unsupported API version '{api_version}'")
146
-
147
-
148
- def _record_summary(
149
- ctx: typer.Context,
150
- *,
151
- command: str,
152
- args: list[str],
153
- server: str,
154
- exit_code: int,
155
- started_at: datetime,
156
- finished_at: datetime,
157
- ) -> None:
158
- cli_ctx = _get_cli_ctx(ctx)
159
- summary = RunSummary(
160
- command=command,
161
- args=args,
162
- server=server,
163
- exit_code=exit_code,
164
- duration_ms=int((finished_at - started_at).total_seconds() * 1000),
165
- started_at=started_at,
166
- finished_at=finished_at,
167
- )
168
- if cli_ctx.reports:
169
- write_reports(summary, base_dir=cli_ctx.report_dir, include_markdown=cli_ctx.markdown)
170
-
171
-
172
- def _emit_json(payload: object) -> None:
173
- text = json.dumps(payload, indent=2, sort_keys=True)
174
- if sys.stdout.isatty():
175
- typer.echo(text)
176
- else:
177
- sys.stdout.write(text + "\n")
178
-
179
-
180
- def _expand_option(value: str | None) -> list[str] | None:
181
- if not value:
182
- return None
183
- return [part.strip() for part in value.split(",") if part.strip()]
184
-
185
-
186
- def _content_summary_args(
187
- *, cql: str | None = None, limit: int | None = None, start: int | None = None, space: str | None = None
188
- ) -> list[str]:
189
- parts: list[str] = []
190
- if cql is not None:
191
- parts.append(cql)
192
- if limit is not None:
193
- parts.append(f"limit={limit}")
194
- if start is not None:
195
- parts.append(f"start={start}")
196
- if space is not None:
197
- parts.append(f"space={space}")
198
- return parts
199
-
200
-
201
- def _read_text_file(path: Path) -> str:
202
- if not path.exists():
203
- raise typer.BadParameter(f"File not found: {path}")
204
- if path.is_dir():
205
- raise typer.BadParameter(f"Expected file but found directory: {path}")
206
- try:
207
- return path.read_text(encoding="utf-8")
208
- except OSError as exc:
209
- raise typer.BadParameter(f"Unable to read file {path}: {exc}") from exc
210
-
211
-
212
- def _parse_json_option(value: str | None, option_name: str) -> dict[str, Any] | None:
213
- if value is None:
214
- return None
215
- try:
216
- parsed = json.loads(value)
217
- except json.JSONDecodeError as exc:
218
- raise typer.BadParameter(f"Invalid JSON for {option_name}: {exc}") from exc
219
- if not isinstance(parsed, dict):
220
- raise typer.BadParameter(f"{option_name} must decode to a JSON object")
221
- return parsed
222
-
223
-
224
- def _parent_context(ctx: typer.Context) -> typer.Context:
225
- return cast("typer.Context", ctx.parent or ctx)
226
-
227
-
228
- # ---------------------------------------------------------------------------
229
- # Typer callbacks & native commands
230
- # ---------------------------------------------------------------------------
231
-
232
-
233
- @app.callback()
234
- def main(
235
- ctx: typer.Context,
236
- report_dir: Path | None = typer.Option(
237
- None, help="Directory for run reports (default: <vds-scripts>/reports/confluence_runs)"
238
- ),
239
- markdown: bool = typer.Option(True, help="Emit Markdown summaries alongside JSON reports"),
240
- reports: bool = typer.Option(True, "--reports/--no-reports", help="Persist run reports to disk"),
241
- json_only: bool = typer.Option(
242
- False,
243
- "--json-only",
244
- help="Emit JSON to stdout only (disables reports and markdown)",
245
- ),
246
- api_version: str = typer.Option("v1", "--api-version", "-A", help="Select REST API version (v1 or v2)"),
247
- structured_logs: bool = typer.Option(
248
- False, "--structured-logs/--no-structured-logs", help="Emit structured JSON logs to stderr"
249
- ),
250
- ) -> None:
251
- resolved = report_dir.resolve() if report_dir else _DEFAULT_REPORT_DIR
252
- version = api_version.lower()
253
- if version not in {"v1", "v2"}:
254
- raise typer.BadParameter("api-version must be one of: v1, v2")
255
- if json_only:
256
- markdown = False
257
- reports = False
258
-
259
- # Configure logging/structlog
260
- if structured_logs or json_only:
261
- configure_structlog(
262
- json_logs=structured_logs, quiet=json_only and not structured_logs, cache_logger=structured_logs
263
- )
264
- if structured_logs:
265
- global logger
266
- logger = structlog.get_logger("confluence_cli") # type: ignore[assignment]
267
-
268
- ctx.obj = CLIContext(report_dir=resolved, markdown=markdown, api_version=version, reports=reports)
269
-
270
-
271
- @app.command("templates")
272
- def cmd_templates(
273
- ctx: typer.Context,
274
- args: list[str] | None = typer.Argument(
275
- None, help="Additional arguments for template operations", show_default=False, metavar="ARGS"
276
- ),
277
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
278
- limit: int = typer.Option(20, "--limit", "-l", help="Number of templates to list"),
279
- space_key: str | None = typer.Option(None, "--space", "-k", help="Space key filter"),
280
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
281
- ) -> None:
282
- """Native Python template management"""
283
- parent_ctx = _parent_context(ctx)
284
- started_at = datetime.now(UTC)
285
-
286
- try:
287
- settings = load_settings(strict=True)
288
- server_key = _normalise_server(server, settings)
289
- client = _build_content_client(settings, server_key, parent_ctx.obj.api_version)
290
-
291
- # Use native Python implementation
292
- if hasattr(client, "list_templates"):
293
- result = client.list_templates(space_key=space_key)
294
- else:
295
- result = {"templates": [], "message": "Templates API not available for this server"}
296
-
297
- if json_output:
298
- _emit_json(result)
299
- else:
300
- templates_payload = []
301
- if isinstance(result, dict):
302
- templates_payload = (
303
- result.get("blueprints")
304
- or result.get("templates")
305
- or result.get("results")
306
- or result.get("contentTemplates")
307
- or []
308
- )
309
- elif isinstance(result, list):
310
- templates_payload = result
311
-
312
- count = len(templates_payload)
313
- typer.echo(f"Found {count} templates:")
314
- for template in templates_payload[:limit]:
315
- if isinstance(template, dict):
316
- name = template.get("name", "Unknown")
317
- template_id = template.get("templateId") or template.get("id") or template.get("uuid") or "Unknown"
318
- else:
319
- name = str(template)
320
- template_id = "Unknown"
321
- typer.echo(f" - {name} (ID: {template_id})")
322
-
323
- exit_code = 0
324
- finished_at = datetime.now(UTC)
325
- _record_summary(
326
- parent_ctx,
327
- command="templates",
328
- args=args or [],
329
- server=server_key,
330
- exit_code=exit_code,
331
- started_at=started_at,
332
- finished_at=finished_at,
333
- )
334
-
335
- if exit_code != 0:
336
- raise typer.Exit(code=exit_code) from None
337
-
338
- except Exception as exc:
339
- logger.exception("templates_command_failed: %s", exc)
340
- typer.echo(f"Error: {exc}", err=True)
341
- raise typer.Exit(code=1) from None
342
-
343
-
344
- @app.command("batch")
345
- def cmd_batch(
346
- _ctx: typer.Context,
347
- _args: list[str] | None = typer.Argument(
348
- None, help="Use 'confluence content batch --help' for available subcommands", show_default=False, metavar="ARGS"
349
- ),
350
- _server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
351
- ) -> None:
352
- """Legacy batch command - use 'confluence content batch' subcommands instead."""
353
- typer.echo("Error: The 'batch' command is deprecated. Use 'confluence content batch' subcommands:", err=True)
354
- typer.echo(" confluence content batch scan --cql '<query>' [options]", err=True)
355
- typer.echo(" confluence content batch snapshot --cql '<query>' [options]", err=True)
356
- raise typer.Exit(code=1) from None
357
-
358
-
359
- @app.command("webhooks")
360
- def cmd_webhooks(
361
- ctx: typer.Context,
362
- args: list[str] | None = typer.Argument(
363
- None, help="Additional arguments for webhook operations", show_default=False, metavar="ARGS"
364
- ),
365
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
366
- list_webhooks: bool = typer.Option(False, "--list", "-l", help="List existing webhooks"),
367
- create_name: str | None = typer.Option(None, "--name", "-n", help="Webhook name"),
368
- create_url: str | None = typer.Option(None, "--url", "-u", help="Webhook URL"),
369
- create_event: str | None = typer.Option(None, "--event", "-e", help="Event type"),
370
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
371
- ) -> None:
372
- """Native Python webhook management"""
373
- parent_ctx = _parent_context(ctx)
374
- started_at = datetime.now(UTC)
375
-
376
- server_key = "internal"
377
- try:
378
- settings = load_settings(strict=True)
379
- server_key = _normalise_server(server, settings)
380
- webhook_client = WebhookClient(_build_http_client(settings, server_key))
381
-
382
- if list_webhooks or (not create_name and not create_url and not create_event):
383
- # List webhooks
384
- result = webhook_client.list()
385
- if json_output or not sys.stdout.isatty():
386
- _emit_json(result)
387
- else:
388
- result_payload = result if isinstance(result, dict) else {"webhooks": result}
389
- webhooks_raw = result_payload.get("webhooks", [])
390
- webhooks = (
391
- [item for item in webhooks_raw if isinstance(item, dict)] if isinstance(webhooks_raw, list) else []
392
- )
393
- count = len(webhooks)
394
- typer.echo(f"Found {count} webhooks:")
395
- for webhook in webhooks:
396
- name = webhook.get("name", "Unknown")
397
- url = webhook.get("url", "Unknown")
398
- events = webhook.get("events", [])
399
- typer.echo(f" - {name}: {url} (events: {', '.join(events)})")
400
-
401
- elif create_name and create_url and create_event:
402
- # Create webhook
403
- result = webhook_client.create(name=create_name, url=create_url, events=[create_event])
404
- if json_output or not sys.stdout.isatty():
405
- _emit_json(result)
406
- else:
407
- webhook_id = result.get("id", "Unknown")
408
- typer.echo(f"Created webhook '{create_name}' with ID: {webhook_id}")
409
-
410
- else:
411
- typer.echo(
412
- "Error: Either use --list to list webhooks or provide --name, --url, and --event to create", err=True
413
- )
414
- raise typer.Exit(code=1) from None
415
-
416
- exit_code = 0
417
- finished_at = datetime.now(UTC)
418
- _record_summary(
419
- parent_ctx,
420
- command="webhooks",
421
- args=args or [],
422
- server=server_key,
423
- exit_code=exit_code,
424
- started_at=started_at,
425
- finished_at=finished_at,
426
- )
427
-
428
- if exit_code != 0:
429
- raise typer.Exit(code=exit_code) from None
430
-
431
- except Exception as exc:
432
- logger.exception("webhooks_command_failed: %s", exc)
433
- typer.echo(f"Error: {exc}", err=True)
434
- raise typer.Exit(code=1) from None
435
-
436
-
437
- @app.command("search")
438
- def cmd_search(
439
- ctx: typer.Context,
440
- args: list[str] | None = typer.Argument(
441
- None, help="Additional arguments for CQL search", show_default=False, metavar="ARGS"
442
- ),
443
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
444
- cql: str = typer.Option(..., "--cql", "-q", help="CQL query string"),
445
- limit: int = typer.Option(25, "--limit", "-l", help="Number of results"),
446
- start: int = typer.Option(0, "--start", help="Pagination start"),
447
- expand: str | None = typer.Option(None, "--expand", help="Comma separated expansions"),
448
- excerpt: str | None = typer.Option(None, "--excerpt", help="Excerpt strategy (e.g., 'highlighted', 'indexed')"),
449
- advanced: bool = typer.Option(False, "--advanced", help="Use advanced CQL search with additional options"),
450
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
451
- ) -> None:
452
- """Native Python CQL search. Use --advanced for additional options like excerpt."""
453
- parent_ctx = _parent_context(ctx)
454
- started_at = datetime.now(UTC)
455
- server_key = "internal"
456
-
457
- try:
458
- settings = load_settings(strict=True)
459
- server_key = _normalise_server(server, settings)
460
- client = _build_content_client(settings, server_key, parent_ctx.obj.api_version)
461
-
462
- # Use native Python implementation
463
- expand_list = _expand_option(expand) if expand else None
464
- if advanced or excerpt:
465
- result = client.cql_advanced(cql, limit=limit, start=start, expand=expand_list, excerpt=excerpt)
466
- else:
467
- result = client.search_cql(cql, limit=limit, start=start, expand=expand_list)
468
-
469
- if json_output or not sys.stdout.isatty():
470
- _emit_json(result)
471
- else:
472
- results = result.get("results", [])
473
- count = len(results)
474
- total = result.get("size", 0)
475
- typer.echo(f"Found {count} of {total} results for CQL: {cql}")
476
- for item in results:
477
- title = item.get("title", "Unknown")
478
- page_id = item.get("id", "Unknown")
479
- space = item.get("space", {}).get("key", "Unknown")
480
- typer.echo(f" - {title} (ID: {page_id}, Space: {space})")
481
-
482
- exit_code = 0
483
- finished_at = datetime.now(UTC)
484
- _record_summary(
485
- parent_ctx,
486
- command="search",
487
- args=args or [],
488
- server=server_key,
489
- exit_code=exit_code,
490
- started_at=started_at,
491
- finished_at=finished_at,
492
- )
493
-
494
- if exit_code != 0:
495
- raise typer.Exit(code=exit_code) from None
496
-
497
- except Exception as exc:
498
- logger.exception("search_command_failed: %s", exc)
499
-
500
-
501
- @content_app.command("child-pages")
502
- def cmd_child_pages(
503
- ctx: typer.Context,
504
- page_id: str = typer.Argument(..., help="Parent page ID"),
505
- expand: str | None = typer.Option(None, "--expand", help="Comma separated expansions"),
506
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
507
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
508
- ) -> None:
509
- """Get child pages using the direct API endpoint (faster than CQL)."""
510
- parent_ctx = _parent_context(ctx)
511
- started_at = datetime.now(UTC)
512
- exit_code = 0
513
- server_key = "internal"
514
-
515
- try:
516
- settings = load_settings(strict=True)
517
- server_key = _normalise_server(server, settings)
518
- client = _build_content_client(settings, server_key, parent_ctx.obj.api_version)
519
- expand_list = _expand_option(expand)
520
-
521
- results = client.get_child_pages(page_id, expand=expand_list)
522
-
523
- if json_output or not sys.stdout.isatty():
524
- _emit_json(results)
525
- else:
526
- count = len(results)
527
- typer.echo(f"Found {count} child pages for {page_id}:")
528
- for item in results:
529
- title = item.get("title", "Unknown")
530
- child_id = item.get("id", "Unknown")
531
- typer.echo(f" - {title} (ID: {child_id})")
532
-
533
- except Exception as exc:
534
- exit_code = 1
535
- logger.exception("child_pages_failed: %s", exc)
536
- typer.echo(f"Error: {exc}", err=True)
537
- finally:
538
- finished_at = datetime.now(UTC)
539
- _record_summary(
540
- parent_ctx,
541
- command="child-pages",
542
- args=[page_id],
543
- server=server_key if "server_key" in locals() else "internal",
544
- exit_code=exit_code,
545
- started_at=started_at,
546
- finished_at=finished_at,
547
- )
548
- if exit_code != 0:
549
- raise typer.Exit(code=exit_code) from None
550
-
551
-
552
- @app.command("search-by-space-type")
553
- def cmd_search_by_space_type(
554
- ctx: typer.Context,
555
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
556
- space_key: str | None = typer.Option(None, "--space", help="Space key to filter by"),
557
- content_type: str | None = typer.Option(None, "--type", help="Content type (e.g., 'page', 'blogpost', 'comment')"),
558
- limit: int = typer.Option(25, "--limit", "-l", help="Number of results"),
559
- start: int = typer.Option(0, "--start", help="Pagination start"),
560
- expand: str | None = typer.Option(None, "--expand", help="Comma separated expansions"),
561
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
562
- ) -> None:
563
- """Search by space and/or content type (helper that builds CQL automatically)."""
564
- parent_ctx = _parent_context(ctx)
565
- started_at = datetime.now(UTC)
566
- exit_code = 0
567
- server_key = "internal"
568
-
569
- try:
570
- if not space_key and not content_type:
571
- raise typer.BadParameter("At least one of --space or --type must be provided")
572
-
573
- settings = load_settings(strict=True)
574
- server_key = _normalise_server(server, settings)
575
- client = _build_content_client(settings, server_key, parent_ctx.obj.api_version)
576
-
577
- expand_list = _expand_option(expand) if expand else None
578
- result = client.search_by_space_and_type(
579
- space_key=space_key,
580
- content_type=content_type,
581
- limit=limit,
582
- start=start,
583
- expand=expand_list,
584
- )
585
-
586
- if json_output or not sys.stdout.isatty():
587
- _emit_json(result)
588
- else:
589
- results = result.get("results", [])
590
- count = len(results)
591
- total = result.get("size", 0)
592
- typer.echo(f"Found {count} of {total} results")
593
- for item in results:
594
- title = item.get("title", "Unknown")
595
- page_id = item.get("id", "Unknown")
596
- space = item.get("space", {}).get("key", "Unknown")
597
- item_type = item.get("type", "Unknown")
598
- typer.echo(f" - {title} (ID: {page_id}, Space: {space}, Type: {item_type})")
599
-
600
- exit_code = 0
601
- except (typer.BadParameter, Exception) as exc:
602
- exit_code = 1
603
- logger.exception("search_by_space_type_failed: %s", exc)
604
- typer.echo(f"Error: {exc}", err=True)
605
- finally:
606
- finished_at = datetime.now(UTC)
607
- args_list: list[str] = []
608
- if space_key:
609
- args_list.append(f"space={space_key}")
610
- if content_type:
611
- args_list.append(f"type={content_type}")
612
- _record_summary(
613
- parent_ctx,
614
- command="search-by-space-type",
615
- args=args_list,
616
- server=server_key,
617
- exit_code=exit_code,
618
- started_at=started_at,
619
- finished_at=finished_at,
620
- )
621
- if exit_code != 0:
622
- raise typer.Exit(code=exit_code) from None
623
-
624
-
625
- @app.command("attachments")
626
- def cmd_attachments(
627
- ctx: typer.Context,
628
- args: list[str] | None = typer.Argument(
629
- None, help="Additional arguments for attachment operations", show_default=False, metavar="ARGS"
630
- ),
631
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
632
- page_id: str | None = typer.Option(None, "--page", "-p", help="Page ID for attachments"),
633
- list_attachments: bool = typer.Option(False, "--list", "-l", help="List attachments for page"),
634
- upload_file: str | None = typer.Option(None, "--upload", "-f", help="File to upload"),
635
- comment: str | None = typer.Option(None, "--comment", "-c", help="Upload comment"),
636
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
637
- ) -> None:
638
- """Native Python attachment management"""
639
- parent_ctx = _parent_context(ctx)
640
- started_at = datetime.now(UTC)
641
-
642
- try:
643
- settings = load_settings(strict=True)
644
- server_key = _normalise_server(server, settings)
645
- client = _build_content_client(settings, server_key, parent_ctx.obj.api_version)
646
-
647
- if list_attachments or (page_id and not upload_file):
648
- # List attachments
649
- if not page_id:
650
- typer.echo("Error: --page ID required for listing attachments", err=True)
651
- raise typer.Exit(code=1) from None
652
-
653
- result = client.list_attachments(page_id)
654
- if json_output or not sys.stdout.isatty():
655
- _emit_json(result)
656
- else:
657
- attachments = result.get("results", [])
658
- count = len(attachments)
659
- typer.echo(f"Found {count} attachments for page {page_id}:")
660
- for attachment in attachments:
661
- name = attachment.get("title", "Unknown")
662
- size = attachment.get("size", 0)
663
- typer.echo(f" - {name} ({size} bytes)")
664
-
665
- elif upload_file and page_id:
666
- # Upload attachment
667
- file_path = Path(upload_file)
668
- if not file_path.exists():
669
- typer.echo(f"Error: File not found: {upload_file}", err=True)
670
- raise typer.Exit(code=1) from None
671
-
672
- result = client.upload_attachment(page_id, file_path, comment=comment)
673
- if json_output or not sys.stdout.isatty():
674
- _emit_json(result)
675
- else:
676
- attachment_id = result.get("id", "Unknown")
677
- typer.echo(f"Uploaded attachment '{file_path.name}' with ID: {attachment_id}")
678
-
679
- else:
680
- typer.echo("Error: Either use --list with --page or provide --page and --upload", err=True)
681
- raise typer.Exit(code=1) from None
682
-
683
- exit_code = 0
684
- finished_at = datetime.now(UTC)
685
- _record_summary(
686
- parent_ctx,
687
- command="attachments",
688
- args=args or [],
689
- server=server_key,
690
- exit_code=exit_code,
691
- started_at=started_at,
692
- finished_at=finished_at,
693
- )
694
-
695
- if exit_code != 0:
696
- raise typer.Exit(code=exit_code) from None
697
-
698
- except Exception as exc:
699
- logger.exception("attachments_command_failed: %s", exc)
700
- typer.echo(f"Error: {exc}", err=True)
701
- raise typer.Exit(code=1) from None
702
-
703
-
704
- @app.command("space-permissions")
705
- def cmd_space_permissions(
706
- ctx: typer.Context,
707
- action: str = typer.Argument(..., help="Action: get, set, remove"),
708
- space_key: str = typer.Option(..., "--space-key", "-k", help="Confluence space key"),
709
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
710
- user_key: str | None = typer.Option(None, "--user", "-u", help="User key for user-targeted operations"),
711
- group_name: str | None = typer.Option(None, "--group", "-g", help="Group name for group-targeted operations"),
712
- anonymous: bool = typer.Option(False, "--anonymous", help="Target anonymous permissions"),
713
- operations: list[str] = typer.Option(
714
- [],
715
- "--operation",
716
- "-o",
717
- help="Space permission operation key (repeatable, e.g., administer, read)",
718
- ),
719
- permissions_file: Path | None = typer.Option(
720
- None,
721
- "--permissions-file",
722
- help="JSON object/array with bulk permission definitions (target.type: user|group|anonymous, operations: [...])",
723
- ),
724
- yes: bool = typer.Option(False, "--yes", help="Confirm write operations"),
725
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
726
- ) -> None:
727
- """Manage Confluence space permissions."""
728
-
729
- parent_ctx = _parent_context(ctx)
730
- started_at = datetime.now(UTC)
731
- exit_code = 0
732
- result_payload: dict[str, Any] = {}
733
- args_summary: list[str] = []
734
- server_key: str | None = None
735
- settings: ConfluenceSettings | None = None
736
-
737
- try:
738
- settings = load_settings(strict=True)
739
- server_key = _normalise_server(server, settings)
740
- client = _build_http_client(settings, server_key)
741
-
742
- resolved_operations = operations or None
743
- args_summary = [
744
- action,
745
- f"space={space_key}",
746
- f"user={user_key}",
747
- f"group={group_name}",
748
- f"anonymous={anonymous}",
749
- f"operations={operations}",
750
- f"permissions_file={permissions_file}",
751
- ]
752
-
753
- if action == "get":
754
- result = client.get_space_permissions(space_key)
755
- result_payload = {"space": space_key, "permissions": result}
756
-
757
- elif action == "set":
758
- if not yes:
759
- raise typer.BadParameter("--yes required for write operations")
760
-
761
- targets = [bool(user_key), bool(group_name), anonymous, bool(permissions_file)]
762
- if sum(1 for flag in targets if flag) != 1:
763
- raise typer.BadParameter(
764
- "Provide exactly one of --user, --group, --anonymous, or --permissions-file for set action"
765
- )
766
-
767
- if permissions_file:
768
- file_content = _read_text_file(permissions_file)
769
- try:
770
- parsed = json.loads(file_content)
771
- except json.JSONDecodeError as exc:
772
- raise typer.BadParameter(f"Invalid JSON in permissions file: {exc}") from exc
773
-
774
- if isinstance(parsed, dict):
775
- items: list[dict[str, Any]] = [parsed]
776
- elif isinstance(parsed, list):
777
- if not all(isinstance(item, dict) for item in parsed):
778
- raise typer.BadParameter("--permissions-file list entries must be JSON objects")
779
- items = parsed # type: ignore[assignment]
780
- else:
781
- raise typer.BadParameter("--permissions-file must contain a JSON object or array")
782
-
783
- result = client.set_permissions_to_multiple_items_for_space(space_key, items)
784
- result_payload = {"space": space_key, "bulk": True, "items_processed": len(items), "result": result}
785
-
786
- elif user_key:
787
- if not resolved_operations:
788
- raise typer.BadParameter("At least one --operation required when setting user permissions")
789
- result = client.set_permissions_to_user_for_space(
790
- space_key,
791
- user_key,
792
- operations=resolved_operations,
793
- )
794
- result_payload = {
795
- "space": space_key,
796
- "target": {"type": "user", "key": user_key},
797
- "operations": resolved_operations,
798
- "result": result,
799
- }
800
-
801
- elif group_name:
802
- if not resolved_operations:
803
- raise typer.BadParameter("At least one --operation required when setting group permissions")
804
- result = client.set_permissions_to_group_for_space(
805
- space_key,
806
- group_name,
807
- operations=resolved_operations,
808
- )
809
- result_payload = {
810
- "space": space_key,
811
- "target": {"type": "group", "name": group_name},
812
- "operations": resolved_operations,
813
- "result": result,
814
- }
815
-
816
- elif anonymous:
817
- if not resolved_operations:
818
- raise typer.BadParameter("At least one --operation required when setting anonymous permissions")
819
- result = client.set_permissions_to_anonymous_for_space(
820
- space_key,
821
- operations=resolved_operations,
822
- )
823
- result_payload = {
824
- "space": space_key,
825
- "target": {"type": "anonymous"},
826
- "operations": resolved_operations,
827
- "result": result,
828
- }
829
-
830
- elif action == "remove":
831
- if not yes:
832
- raise typer.BadParameter("--yes required for write operations")
833
-
834
- targets = [bool(user_key), bool(group_name), anonymous]
835
- if sum(1 for flag in targets if flag) != 1:
836
- raise typer.BadParameter("Provide exactly one of --user, --group, or --anonymous for remove action")
837
-
838
- if user_key:
839
- result = client.remove_permissions_from_user_for_space(space_key, user_key)
840
- result_payload = {
841
- "space": space_key,
842
- "target": {"type": "user", "key": user_key},
843
- "result": result,
844
- }
845
-
846
- elif group_name:
847
- result = client.remove_permissions_from_group_for_space(space_key, group_name)
848
- result_payload = {
849
- "space": space_key,
850
- "target": {"type": "group", "name": group_name},
851
- "result": result,
852
- }
853
-
854
- elif anonymous:
855
- result = client.remove_permissions_from_anonymous_for_space(space_key)
856
- result_payload = {
857
- "space": space_key,
858
- "target": {"type": "anonymous"},
859
- "result": result,
860
- }
861
-
862
- else:
863
- raise typer.BadParameter(f"Unknown action: {action}")
864
-
865
- if json_output or not sys.stdout.isatty():
866
- _emit_json(result_payload)
867
- else:
868
- typer.echo(json.dumps(result_payload, indent=2, sort_keys=True))
869
-
870
- except (VDSClientError, typer.BadParameter) as exc:
871
- exit_code = 1
872
- logger.exception("space_permissions_command_failed: %s", exc)
873
- typer.echo(f"Error: {exc}", err=True)
874
- except Exception as exc: # pragma: no cover - unexpected errors
875
- exit_code = 1
876
- logger.exception("space_permissions_command_unexpected")
877
- typer.echo(f"Error: {exc}", err=True)
878
- finally:
879
- finished_at = datetime.now(UTC)
880
- server_label = server_key or (server.lower() if server else "internal")
881
- _record_summary(
882
- parent_ctx,
883
- command="space-permissions",
884
- args=args_summary,
885
- server=server_label,
886
- exit_code=exit_code,
887
- started_at=started_at,
888
- finished_at=finished_at,
889
- )
890
- if exit_code != 0:
891
- raise typer.Exit(code=exit_code) from None
892
-
893
-
894
- @app.command("space-management")
895
- def cmd_space_management(
896
- ctx: typer.Context,
897
- action: str = typer.Argument(..., help="Action: archive, trash-list, trash-remove"),
898
- space_key: str = typer.Option(..., "--space-key", "-k", help="Confluence space key"),
899
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
900
- cursor: str | None = typer.Option(None, "--cursor", help="Pagination cursor for trash-list"),
901
- limit: int = typer.Option(50, "--limit", help="Limit for trash-list (max 100)"),
902
- expand: str | None = typer.Option(None, "--expand", help="Comma separated expansions for trash-list"),
903
- yes: bool = typer.Option(False, "--yes", help="Confirm write operations"),
904
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
905
- ) -> None:
906
- """Manage Confluence space lifecycle operations."""
907
-
908
- parent_ctx = _parent_context(ctx)
909
- started_at = datetime.now(UTC)
910
- exit_code = 0
911
- result_payload: dict[str, Any] = {}
912
- args_summary: list[str] = []
913
- server_key: str | None = None
914
- settings: ConfluenceSettings | None = None
915
-
916
- try:
917
- if limit < 1 or limit > 100:
918
- raise typer.BadParameter("--limit must be between 1 and 100")
919
-
920
- settings = load_settings(strict=True)
921
- server_key = _normalise_server(server, settings)
922
- client = _build_http_client(settings, server_key)
923
-
924
- expand_value = expand if expand else None
925
- args_summary = [
926
- action,
927
- f"space={space_key}",
928
- f"cursor={cursor}",
929
- f"limit={limit}",
930
- f"expand={expand_value}",
931
- ]
932
-
933
- if action == "archive":
934
- if not yes:
935
- raise typer.BadParameter("--yes required for archive")
936
- result = client.archive_space(space_key)
937
- result_payload = {"space": space_key, "action": "archive", "result": result}
938
-
939
- elif action == "trash-list":
940
- result = client.get_trashed_contents_by_space(
941
- space_key,
942
- cursor=cursor,
943
- expand=expand_value,
944
- limit=limit,
945
- )
946
- result_payload = {
947
- "space": space_key,
948
- "action": "trash-list",
949
- "result": result,
950
- }
951
-
952
- elif action == "trash-remove":
953
- if not yes:
954
- raise typer.BadParameter("--yes required for trash-remove")
955
- result = client.remove_trashed_contents_by_space(space_key)
956
- result_payload = {"space": space_key, "action": "trash-remove", "result": result}
957
-
958
- else:
959
- raise typer.BadParameter(f"Unknown action: {action}")
960
-
961
- if json_output or not sys.stdout.isatty():
962
- _emit_json(result_payload)
963
- else:
964
- typer.echo(json.dumps(result_payload, indent=2, sort_keys=True))
965
-
966
- except (VDSClientError, typer.BadParameter) as exc:
967
- exit_code = 1
968
- logger.exception("space_management_failed: %s", exc)
969
- typer.echo(f"Error: {exc}", err=True)
970
- except Exception as exc: # pragma: no cover - unexpected errors
971
- exit_code = 1
972
- logger.exception("space_management_unexpected_error")
973
- typer.echo(f"Error: {exc}", err=True)
974
- finally:
975
- finished_at = datetime.now(UTC)
976
- server_label = server_key or (server.lower() if server else "internal")
977
- _record_summary(
978
- parent_ctx,
979
- command="space-management",
980
- args=args_summary,
981
- server=server_label,
982
- exit_code=exit_code,
983
- started_at=started_at,
984
- finished_at=finished_at,
985
- )
986
- if exit_code != 0:
987
- raise typer.Exit(code=exit_code) from None
988
-
989
-
990
- @app.command("group")
991
- def cmd_group(
992
- ctx: typer.Context,
993
- action: str = typer.Argument(..., help="Action: list, members"),
994
- group_name: str | None = typer.Option(None, "--group", "-g", help="Group name (for members)"),
995
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
996
- start: int = typer.Option(0, "--start", help="Start index for pagination"),
997
- limit: int = typer.Option(1000, "--limit", help="Limit for pagination (max 1000)"),
998
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
999
- ) -> None:
1000
- """Manage Confluence groups."""
1001
- parent_ctx = _parent_context(ctx)
1002
- started_at = datetime.now(UTC)
1003
- exit_code = 0
1004
- result_payload: dict[str, Any] = {}
1005
- args_summary: list[str] = []
1006
- server_key: str | None = None
1007
- settings: ConfluenceSettings | None = None
1008
-
1009
- try:
1010
- if limit < 1 or limit > 1000:
1011
- raise typer.BadParameter("--limit must be between 1 and 1000")
1012
-
1013
- settings = load_settings(strict=True)
1014
- server_key = _normalise_server(server, settings)
1015
- client = _build_http_client(settings, server_key)
1016
-
1017
- args_summary = [action, f"start={start}", f"limit={limit}"]
1018
-
1019
- if action == "list":
1020
- result = client.get_all_groups(start=start, limit=limit)
1021
- result_payload = {"count": len(result), "groups": result}
1022
-
1023
- elif action == "members":
1024
- if not group_name:
1025
- raise typer.BadParameter("--group required for members action")
1026
- args_summary.append(f"group={group_name}")
1027
- result = client.get_group_members(group_name, start=start, limit=limit)
1028
- result_payload = {"group": group_name, "count": len(result), "members": result}
1029
-
1030
- else:
1031
- raise typer.BadParameter(f"Unknown action: {action}")
1032
-
1033
- if json_output or not sys.stdout.isatty():
1034
- _emit_json(result_payload)
1035
- else:
1036
- typer.echo(json.dumps(result_payload, indent=2, sort_keys=True))
1037
-
1038
- except (VDSClientError, typer.BadParameter) as exc:
1039
- exit_code = 1
1040
- logger.exception("group_failed: %s", exc)
1041
- typer.echo(f"Error: {exc}", err=True)
1042
- except Exception as exc: # pragma: no cover - unexpected errors
1043
- exit_code = 1
1044
- logger.exception("group_unexpected_error")
1045
- typer.echo(f"Error: {exc}", err=True)
1046
- finally:
1047
- finished_at = datetime.now(UTC)
1048
- server_label = server_key or (server.lower() if server else "internal")
1049
- _record_summary(
1050
- parent_ctx,
1051
- command="group",
1052
- args=args_summary,
1053
- server=server_label,
1054
- exit_code=exit_code,
1055
- started_at=started_at,
1056
- finished_at=finished_at,
1057
- )
1058
- if exit_code != 0:
1059
- raise typer.Exit(code=exit_code) from None
1060
-
1061
-
1062
- @app.command("user")
1063
- def cmd_user(
1064
- ctx: typer.Context,
1065
- action: str = typer.Argument(..., help="Action: get, password, group-add, group-remove"),
1066
- username: str | None = typer.Option(None, "--username", "-u", help="Username"),
1067
- userkey: str | None = typer.Option(None, "--userkey", help="User key"),
1068
- group_name: str | None = typer.Option(None, "--group", "-g", help="Group name (for group-add/group-remove)"),
1069
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
1070
- expand: str | None = typer.Option(None, "--expand", help="Comma-separated fields to expand (for get)"),
1071
- new_password: str | None = typer.Option(None, "--new-password", help="New password (for password)"),
1072
- yes: bool = typer.Option(False, "--yes", help="Confirm write operations"),
1073
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
1074
- ) -> None:
1075
- """Manage Confluence users."""
1076
- parent_ctx = _parent_context(ctx)
1077
- started_at = datetime.now(UTC)
1078
- exit_code = 0
1079
- result_payload: dict[str, Any] = {}
1080
- args_summary: list[str] = []
1081
- server_key: str | None = None
1082
- settings: ConfluenceSettings | None = None
1083
-
1084
- try:
1085
- settings = load_settings(strict=True)
1086
- server_key = _normalise_server(server, settings)
1087
- client = _build_http_client(settings, server_key)
1088
-
1089
- args_summary = [action]
1090
-
1091
- if action == "get":
1092
- if not username and not userkey:
1093
- raise typer.BadParameter("Provide --username or --userkey for get action")
1094
- if username and userkey:
1095
- raise typer.BadParameter("Provide either --username or --userkey, not both")
1096
- expand_value = expand if expand else None
1097
- args_summary.append(f"username={username}" if username else f"userkey={userkey}")
1098
- if expand_value:
1099
- args_summary.append(f"expand={expand_value}")
1100
-
1101
- if username:
1102
- result = client.get_user_details_by_username(username, expand=expand_value)
1103
- else:
1104
- assert userkey is not None
1105
- result = client.get_user_details_by_userkey(userkey, expand=expand_value)
1106
- result_payload = {"user": result}
1107
-
1108
- elif action == "password":
1109
- if not yes:
1110
- raise typer.BadParameter("--yes required for password change")
1111
- if not username:
1112
- raise typer.BadParameter("--username required for password action")
1113
- if not new_password:
1114
- raise typer.BadParameter("--new-password required for password action")
1115
- args_summary.append(f"username={username}")
1116
- client.change_user_password(username, new_password)
1117
- result_payload = {"username": username, "status": "password_changed"}
1118
-
1119
- elif action == "group-add":
1120
- if not yes:
1121
- raise typer.BadParameter("--yes required for group-add")
1122
- if not username:
1123
- raise typer.BadParameter("--username required for group-add")
1124
- if not group_name:
1125
- raise typer.BadParameter("--group required for group-add")
1126
- args_summary.append(f"username={username}")
1127
- args_summary.append(f"group={group_name}")
1128
- client.add_user_to_group(username, group_name)
1129
- result_payload = {"username": username, "group": group_name, "status": "added"}
1130
-
1131
- elif action == "group-remove":
1132
- if not yes:
1133
- raise typer.BadParameter("--yes required for group-remove")
1134
- if not username:
1135
- raise typer.BadParameter("--username required for group-remove")
1136
- if not group_name:
1137
- raise typer.BadParameter("--group required for group-remove")
1138
- args_summary.append(f"username={username}")
1139
- args_summary.append(f"group={group_name}")
1140
- client.remove_user_from_group(username, group_name)
1141
- result_payload = {"username": username, "group": group_name, "status": "removed"}
1142
-
1143
- else:
1144
- raise typer.BadParameter(f"Unknown action: {action}")
1145
-
1146
- if json_output or not sys.stdout.isatty():
1147
- _emit_json(result_payload)
1148
- else:
1149
- typer.echo(json.dumps(result_payload, indent=2, sort_keys=True))
1150
-
1151
- except (VDSClientError, typer.BadParameter) as exc:
1152
- exit_code = 1
1153
- logger.exception("user_failed: %s", exc)
1154
- typer.echo(f"Error: {exc}", err=True)
1155
- except Exception as exc: # pragma: no cover - unexpected errors
1156
- exit_code = 1
1157
- logger.exception("user_unexpected_error")
1158
- typer.echo(f"Error: {exc}", err=True)
1159
- finally:
1160
- finished_at = datetime.now(UTC)
1161
- server_label = server_key or (server.lower() if server else "internal")
1162
- _record_summary(
1163
- parent_ctx,
1164
- command="user",
1165
- args=args_summary,
1166
- server=server_label,
1167
- exit_code=exit_code,
1168
- started_at=started_at,
1169
- finished_at=finished_at,
1170
- )
1171
- if exit_code != 0:
1172
- raise typer.Exit(code=exit_code) from None
1173
-
1174
-
1175
- @app.command("export")
1176
- def cmd_export(
1177
- ctx: typer.Context,
1178
- action: str = typer.Argument(..., help="Action: page, space"),
1179
- page_id: str | None = typer.Option(None, "--page-id", help="Page ID (for page)"),
1180
- space_key: str | None = typer.Option(None, "--space-key", "-k", help="Space key (for space)"),
1181
- export_type: str | None = typer.Option(None, "--export-type", help="Export type: pdf, html, xml (for space)"),
1182
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
1183
- output: Path | None = typer.Option(None, "--output", "-o", help="Output file path (for page PDF)"),
1184
- api_version: str | None = typer.Option(
1185
- None, "--api-version", help="API version: cloud, server (for page, auto-detected if not specified)"
1186
- ),
1187
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
1188
- ) -> None:
1189
- """Export Confluence pages or spaces."""
1190
- parent_ctx = _parent_context(ctx)
1191
- started_at = datetime.now(UTC)
1192
- exit_code = 0
1193
- result_payload: dict[str, Any] = {}
1194
- args_summary: list[str] = []
1195
- server_key: str | None = None
1196
- settings: ConfluenceSettings | None = None
1197
-
1198
- try:
1199
- settings = load_settings(strict=True)
1200
- server_key = _normalise_server(server, settings)
1201
- client = _build_http_client(settings, server_key)
1202
-
1203
- args_summary = [action]
1204
-
1205
- if action == "page":
1206
- if not page_id:
1207
- raise typer.BadParameter("--page-id required for page action")
1208
- args_summary.append(f"page_id={page_id}")
1209
- if api_version:
1210
- args_summary.append(f"api_version={api_version}")
1211
-
1212
- pdf_bytes = client.export_page(page_id, api_version=api_version)
1213
-
1214
- if output:
1215
- output.write_bytes(pdf_bytes)
1216
- result_payload = {"page_id": page_id, "output_file": str(output), "size_bytes": len(pdf_bytes)}
1217
- typer.echo(f"Exported page {page_id} to {output} ({len(pdf_bytes)} bytes)")
1218
- else:
1219
- # Write to stdout as binary
1220
- sys.stdout.buffer.write(pdf_bytes)
1221
- result_payload = {"page_id": page_id, "size_bytes": len(pdf_bytes), "format": "pdf"}
1222
-
1223
- elif action == "space":
1224
- if not space_key:
1225
- raise typer.BadParameter("--space-key required for space action")
1226
- if not export_type:
1227
- raise typer.BadParameter("--export-type required for space action")
1228
- if export_type not in ("pdf", "html", "xml"):
1229
- raise typer.BadParameter("--export-type must be one of: pdf, html, xml")
1230
- args_summary.append(f"space_key={space_key}")
1231
- args_summary.append(f"export_type={export_type}")
1232
-
1233
- download_url = client.get_space_export(space_key, export_type)
1234
- result_payload = {"space_key": space_key, "export_type": export_type, "download_url": download_url}
1235
-
1236
- if json_output or not sys.stdout.isatty():
1237
- _emit_json(result_payload)
1238
- else:
1239
- typer.echo(f"Space export URL: {download_url}")
1240
-
1241
- else:
1242
- raise typer.BadParameter(f"Unknown action: {action}")
1243
-
1244
- # For page action, JSON output only if explicitly requested or output file specified
1245
- if action == "page" and (json_output or output) and json_output:
1246
- _emit_json(result_payload)
1247
-
1248
- except (VDSClientError, typer.BadParameter) as exc:
1249
- exit_code = 1
1250
- logger.exception("export_failed: %s", exc)
1251
- typer.echo(f"Error: {exc}", err=True)
1252
- except Exception as exc: # pragma: no cover - unexpected errors
1253
- exit_code = 1
1254
- logger.exception("export_unexpected_error")
1255
- typer.echo(f"Error: {exc}", err=True)
1256
- finally:
1257
- finished_at = datetime.now(UTC)
1258
- server_label = server_key or (server.lower() if server else "internal")
1259
- _record_summary(
1260
- parent_ctx,
1261
- command="export",
1262
- args=args_summary,
1263
- server=server_label,
1264
- exit_code=exit_code,
1265
- started_at=started_at,
1266
- finished_at=finished_at,
1267
- )
1268
- if exit_code != 0:
1269
- raise typer.Exit(code=exit_code) from None
1270
-
1271
-
1272
- @app.command("crawl-tree")
1273
- def cmd_crawl_tree(
1274
- ctx: typer.Context,
1275
- root: str = typer.Argument(..., help="Root page reference (numeric ID, ?pageId= URL, or /display/<SPACE>/<Title>)"),
1276
- output_dir: Path = typer.Option(..., "--out", "-o", help="Output directory for downloaded pages/attachments"),
1277
- depth: int = typer.Option(
1278
- 3,
1279
- "--depth",
1280
- "--crawl-max-depth",
1281
- min=0,
1282
- max=20,
1283
- help="Recursive child-page crawl depth (0 = only root).",
1284
- ),
1285
- include_attachments: bool = typer.Option(
1286
- True,
1287
- "--include-attachments/--no-include-attachments",
1288
- help="Download attachments for each visited page",
1289
- ),
1290
- emit_corpus: bool = typer.Option(
1291
- False,
1292
- "--emit-corpus/--no-emit-corpus",
1293
- help="Emit `corpus.jsonl` chunked by headings for LLM ingestion",
1294
- ),
1295
- emit_link_graph: bool = typer.Option(
1296
- False,
1297
- "--emit-link-graph/--no-emit-link-graph",
1298
- help="Emit `link-graph.json` (normalized outbound links) for doc↔code alignment",
1299
- ),
1300
- emit_tables: bool = typer.Option(
1301
- False,
1302
- "--emit-tables",
1303
- help="Emit `tables.jsonl` (extracted HTML tables) for downstream analysis",
1304
- ),
1305
- emit_mentions: bool = typer.Option(
1306
- False,
1307
- "--emit-mentions",
1308
- help="Emit `mentions.jsonl` (cross-system refs: Confluence/Jira/Bitbucket/external/email) for downstream analysis",
1309
- ),
1310
- body_format: str = typer.Option(
1311
- "view",
1312
- "--body-format",
1313
- help="Body representation to store/analyze: view|export_view|storage (default: view)",
1314
- ),
1315
- chunk_max_chars: int = typer.Option(
1316
- 4000,
1317
- "--chunk-max-chars",
1318
- help="Max characters per corpus chunk (emit-corpus only). Oversized heading chunks are split into ordered subchunks (0 disables splitting).",
1319
- ),
1320
- cache_mode: str = typer.Option(
1321
- "read-write",
1322
- "--cache-mode",
1323
- help="Compatibility cache mode flag (off|read|read-write|refresh) for downstream orchestrators.",
1324
- ),
1325
- cache_ttl_hours: int | None = typer.Option(
1326
- None,
1327
- "--cache-ttl-hours",
1328
- min=1,
1329
- help="Compatibility cache TTL (hours) for downstream orchestrators.",
1330
- ),
1331
- incremental: bool = typer.Option(
1332
- True,
1333
- "--incremental/--no-incremental",
1334
- help="Compatibility incremental mode flag; enables resume semantics by default.",
1335
- ),
1336
- incremental_overlap_minutes: int = typer.Option(
1337
- 5,
1338
- "--incremental-overlap-minutes",
1339
- min=0,
1340
- help="Incremental crawl overlap window in minutes for last-modified high-water mark refresh.",
1341
- ),
1342
- full_reconciliation_interval_days: int = typer.Option(
1343
- 7,
1344
- "--full-reconciliation-interval-days",
1345
- min=1,
1346
- help="Interval in days for full reconciliation sweep when incremental mode is enabled.",
1347
- ),
1348
- content_root: Path | None = typer.Option(
1349
- None,
1350
- "--content-root",
1351
- help="Compatibility content root for downstream orchestrators (diagnostic metadata only).",
1352
- ),
1353
- project_storage_key: str | None = typer.Option(
1354
- None,
1355
- "--project-storage-key",
1356
- help="Compatibility project storage namespace key (diagnostic metadata only).",
1357
- ),
1358
- resume: bool = typer.Option(
1359
- False,
1360
- "--resume",
1361
- help="Resume from previous crawl state; skip unchanged pages (TSK-188)",
1362
- ),
1363
- max_nodes: int | None = typer.Option(
1364
- 500,
1365
- "--max-nodes",
1366
- "--crawl-max-nodes",
1367
- min=1,
1368
- help="Safety limit: max pages to process before stopping (default: 500).",
1369
- ),
1370
- page_concurrency: int = typer.Option(
1371
- 5,
1372
- "--page-concurrency",
1373
- "--crawl-concurrency",
1374
- min=1,
1375
- help="Bounded page fetch concurrency (default: 5).",
1376
- ),
1377
- staged_mode: str = typer.Option(
1378
- "off",
1379
- "--staged-mode",
1380
- "--staged-crawl-mode",
1381
- help="Optional staged crawl mode: off|structure-first (default: off).",
1382
- ),
1383
- rate_limit_budget: int = typer.Option(
1384
- 50000,
1385
- "--rate-limit-budget",
1386
- min=100,
1387
- help="Hourly Confluence API points budget used for proactive crawl throttling.",
1388
- ),
1389
- bundle: bool = typer.Option(
1390
- False,
1391
- "--bundle",
1392
- help="Create zip bundle of all artifacts for offline handoff (TSK-189)",
1393
- ),
1394
- manifest_path: Path | None = typer.Option(
1395
- None,
1396
- "--manifest",
1397
- help="Optional manifest file path (default: <out>/crawl_manifest.json)",
1398
- ),
1399
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
1400
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
1401
- ) -> None:
1402
- """Crawl a Confluence page tree and download content + attachments to disk."""
1403
- parent_ctx = _parent_context(ctx)
1404
- started_at = datetime.now(UTC)
1405
- exit_code = 0
1406
- server_key: str | None = None
1407
- result_payload: dict[str, Any] = {}
1408
- args_summary: list[str] = []
1409
-
1410
- try:
1411
- settings = load_settings(strict=True)
1412
- if server is None:
1413
- inferred = _infer_server_from_root_ref(root, settings)
1414
- if inferred:
1415
- server = inferred
1416
- server_key = _normalise_server(server, settings)
1417
- client = _build_http_client(settings, server_key)
1418
-
1419
- body_format = (body_format or "view").strip().lower().replace("-", "_")
1420
- if body_format not in {"view", "export_view", "storage"}:
1421
- raise typer.BadParameter("--body-format must be one of: view, export_view, storage")
1422
- cache_mode = (cache_mode or "read-write").strip().lower()
1423
- if cache_mode not in {"off", "read", "read-write", "refresh"}:
1424
- raise typer.BadParameter("--cache-mode must be one of: off, read, read-write, refresh")
1425
- staged_mode = (staged_mode or "off").strip().lower().replace("-", "_")
1426
- if staged_mode not in {"off", "structure_first"}:
1427
- raise typer.BadParameter("--staged-mode must be one of: off, structure-first")
1428
- if chunk_max_chars < 0:
1429
- raise typer.BadParameter("--chunk-max-chars must be >= 0")
1430
- effective_resume = bool(resume or incremental)
1431
-
1432
- args_summary = [
1433
- root,
1434
- f"depth={depth}",
1435
- f"out={output_dir!s}",
1436
- f"attachments={include_attachments}",
1437
- f"body_format={body_format}",
1438
- f"chunk_max_chars={chunk_max_chars}",
1439
- f"resume={resume}",
1440
- f"incremental={incremental}",
1441
- f"incremental_overlap_minutes={incremental_overlap_minutes}",
1442
- f"full_reconciliation_interval_days={full_reconciliation_interval_days}",
1443
- f"effective_resume={effective_resume}",
1444
- f"cache_mode={cache_mode}",
1445
- f"cache_ttl_hours={cache_ttl_hours}",
1446
- f"content_root={content_root}",
1447
- f"project_storage_key={project_storage_key}",
1448
- f"max_nodes={max_nodes}",
1449
- f"page_concurrency={page_concurrency}",
1450
- f"staged_mode={staged_mode}",
1451
- f"rate_limit_budget={rate_limit_budget}",
1452
- f"bundle={bundle}",
1453
- ]
1454
-
1455
- runtime_event_logger = logging.getLogger("confluence_cli.crawl_tree")
1456
-
1457
- def _runtime_event_sink(event_name: str, payload: dict[str, Any]) -> None:
1458
- runtime_event_logger.info(
1459
- "crawl_tree_runtime_event %s %s",
1460
- event_name,
1461
- json.dumps(payload, ensure_ascii=False, sort_keys=True),
1462
- )
1463
-
1464
- result_payload = crawl_tree_to_disk(
1465
- http=client,
1466
- root_ref=root,
1467
- output_dir=output_dir,
1468
- options=CrawlOptions(
1469
- max_depth=depth,
1470
- include_attachments=include_attachments,
1471
- emit_corpus=emit_corpus,
1472
- emit_link_graph=emit_link_graph,
1473
- emit_tables=emit_tables,
1474
- emit_mentions=emit_mentions,
1475
- body_format=body_format,
1476
- chunk_max_chars=None if chunk_max_chars == 0 else chunk_max_chars,
1477
- resume=effective_resume,
1478
- max_nodes=max_nodes,
1479
- page_concurrency=page_concurrency,
1480
- staged_mode=staged_mode,
1481
- incremental_cql=incremental,
1482
- incremental_overlap_minutes=incremental_overlap_minutes,
1483
- full_reconciliation_interval_days=full_reconciliation_interval_days,
1484
- rate_limit_budget=rate_limit_budget,
1485
- runtime_event_sink=_runtime_event_sink,
1486
- bundle=bundle,
1487
- ),
1488
- manifest_path=manifest_path,
1489
- )
1490
- result_payload["cache"] = {
1491
- "mode": cache_mode,
1492
- "ttl_hours": cache_ttl_hours,
1493
- "incremental": incremental,
1494
- "incremental_overlap_minutes": incremental_overlap_minutes,
1495
- "full_reconciliation_interval_days": full_reconciliation_interval_days,
1496
- "effective_resume": effective_resume,
1497
- "content_root": str(content_root) if content_root else None,
1498
- "project_storage_key": project_storage_key,
1499
- }
1500
-
1501
- if json_output or not sys.stdout.isatty():
1502
- _emit_json(result_payload)
1503
- else:
1504
- root_id = result_payload.get("root_page_id")
1505
- pages = 1 + len(result_payload.get("child_pages") or [])
1506
- atts = len(result_payload.get("attachments") or [])
1507
- resume_state = result_payload.get("resume_state") or {}
1508
- skipped = resume_state.get("skipped_unchanged", 0)
1509
- typer.echo(f"Crawled {pages} page(s), downloaded {atts} attachment(s). Root: {root_id}.")
1510
- if skipped > 0:
1511
- typer.echo(f"Skipped {skipped} unchanged page(s) (resume mode).")
1512
- if max_nodes and not resume_state.get("completed", True):
1513
- typer.echo(f"Stopped at max_nodes={max_nodes}. Use --resume to continue.")
1514
- typer.echo(f"Output: {result_payload.get('out_dir')}")
1515
- if result_payload.get("bundle_path"):
1516
- typer.echo(f"Bundle: {result_payload.get('bundle_path')}")
1517
-
1518
- except (VDSClientError, typer.BadParameter) as exc:
1519
- exit_code = 1
1520
- logger.exception("crawl_tree_failed: %s", exc)
1521
- typer.echo(f"Error: {exc}", err=True)
1522
- except Exception as exc: # pragma: no cover - unexpected errors
1523
- exit_code = 1
1524
- logger.exception("crawl_tree_unexpected_error")
1525
- typer.echo(f"Error: {exc}", err=True)
1526
- finally:
1527
- finished_at = datetime.now(UTC)
1528
- server_label = server_key or (server.lower() if server else "internal")
1529
- _record_summary(
1530
- parent_ctx,
1531
- command="crawl-tree",
1532
- args=args_summary,
1533
- server=server_label,
1534
- exit_code=exit_code,
1535
- started_at=started_at,
1536
- finished_at=finished_at,
1537
- )
1538
- if exit_code != 0:
1539
- raise typer.Exit(code=exit_code) from None
1540
-
1541
-
1542
- @app.command("draft")
1543
- def cmd_draft(
1544
- ctx: typer.Context,
1545
- action: str = typer.Argument(..., help="Action: get, list, remove"),
1546
- page_id: str | None = typer.Option(None, "--page-id", help="Page ID (for get/remove)"),
1547
- space_key: str | None = typer.Option(None, "--space-key", "-k", help="Space key (for list)"),
1548
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
1549
- limit: int = typer.Option(25, "--limit", help="Limit for list (max 100)"),
1550
- yes: bool = typer.Option(False, "--yes", help="Confirm write operations (for remove)"),
1551
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
1552
- ) -> None:
1553
- """Manage Confluence draft pages (Server-only)."""
1554
- parent_ctx = _parent_context(ctx)
1555
- started_at = datetime.now(UTC)
1556
- exit_code = 0
1557
- result_payload: dict[str, Any] = {}
1558
- args_summary: list[str] = []
1559
- server_key: str | None = None
1560
- settings: ConfluenceSettings | None = None
1561
-
1562
- try:
1563
- if limit < 1 or limit > 100:
1564
- raise typer.BadParameter("--limit must be between 1 and 100")
1565
-
1566
- settings = load_settings(strict=True)
1567
- server_key = _normalise_server(server, settings)
1568
- client = _build_http_client(settings, server_key)
1569
-
1570
- args_summary = [action]
1571
-
1572
- if action == "get":
1573
- if not page_id:
1574
- raise typer.BadParameter("--page-id required for get action")
1575
- args_summary.append(f"page_id={page_id}")
1576
- result = client.get_draft_page_by_id(page_id)
1577
- result_payload = {"draft_page": result}
1578
-
1579
- elif action == "list":
1580
- if not space_key:
1581
- raise typer.BadParameter("--space-key required for list action")
1582
- args_summary.append(f"space_key={space_key}")
1583
- args_summary.append(f"limit={limit}")
1584
- result = client.get_all_draft_pages_from_space(space_key, limit=limit)
1585
- result_payload = {"space": space_key, "count": len(result), "drafts": result}
1586
-
1587
- elif action == "remove":
1588
- if not yes:
1589
- raise typer.BadParameter("--yes required for remove action")
1590
- if not page_id:
1591
- raise typer.BadParameter("--page-id required for remove action")
1592
- args_summary.append(f"page_id={page_id}")
1593
- client.remove_page_as_draft(page_id)
1594
- result_payload = {"page_id": page_id, "status": "removed"}
1595
-
1596
- else:
1597
- raise typer.BadParameter(f"Unknown action: {action}")
1598
-
1599
- if json_output or not sys.stdout.isatty():
1600
- _emit_json(result_payload)
1601
- else:
1602
- typer.echo(json.dumps(result_payload, indent=2, sort_keys=True))
1603
-
1604
- except (VDSClientError, typer.BadParameter) as exc:
1605
- exit_code = 1
1606
- logger.exception("draft_failed: %s", exc)
1607
- typer.echo(f"Error: {exc}", err=True)
1608
- except Exception as exc: # pragma: no cover - unexpected errors
1609
- exit_code = 1
1610
- logger.exception("draft_unexpected_error")
1611
- typer.echo(f"Error: {exc}", err=True)
1612
- finally:
1613
- finished_at = datetime.now(UTC)
1614
- server_label = server_key or (server.lower() if server else "internal")
1615
- _record_summary(
1616
- parent_ctx,
1617
- command="draft",
1618
- args=args_summary,
1619
- server=server_label,
1620
- exit_code=exit_code,
1621
- started_at=started_at,
1622
- finished_at=finished_at,
1623
- )
1624
- if exit_code != 0:
1625
- raise typer.Exit(code=exit_code) from None
1626
-
1627
-
1628
- @app.command("history")
1629
- def cmd_history(
1630
- ctx: typer.Context,
1631
- action: str = typer.Argument(..., help="Action: get, version, remove"),
1632
- page_id: str | None = typer.Option(None, "--page-id", help="Page ID"),
1633
- version: int | None = typer.Option(None, "--version", help="Version number (for version/remove)"),
1634
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
1635
- yes: bool = typer.Option(False, "--yes", help="Confirm write operations (for remove)"),
1636
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
1637
- ) -> None:
1638
- """Manage Confluence page history and versioning."""
1639
- parent_ctx = _parent_context(ctx)
1640
- started_at = datetime.now(UTC)
1641
- exit_code = 0
1642
- result_payload: dict[str, Any] = {}
1643
- args_summary: list[str] = []
1644
- server_key: str | None = None
1645
- settings: ConfluenceSettings | None = None
1646
-
1647
- try:
1648
- settings = load_settings(strict=True)
1649
- server_key = _normalise_server(server, settings)
1650
- client = _build_http_client(settings, server_key)
1651
-
1652
- args_summary = [action]
1653
-
1654
- if action == "get":
1655
- if not page_id:
1656
- raise typer.BadParameter("--page-id required for get action")
1657
- args_summary.append(f"page_id={page_id}")
1658
- result = client.history(page_id)
1659
- result_payload = {"page_id": page_id, "history": result}
1660
-
1661
- elif action == "version":
1662
- if not page_id:
1663
- raise typer.BadParameter("--page-id required for version action")
1664
- if version is None:
1665
- raise typer.BadParameter("--version required for version action")
1666
- args_summary.append(f"page_id={page_id}")
1667
- args_summary.append(f"version={version}")
1668
- result = client.get_content_history_by_version_number(page_id, version)
1669
- result_payload = {"page_id": page_id, "version": version, "content": result}
1670
-
1671
- elif action == "remove":
1672
- if not yes:
1673
- raise typer.BadParameter("--yes required for remove action (experimental feature)")
1674
- if not page_id:
1675
- raise typer.BadParameter("--page-id required for remove action")
1676
- if version is None:
1677
- raise typer.BadParameter("--version required for remove action")
1678
- args_summary.append(f"page_id={page_id}")
1679
- args_summary.append(f"version={version}")
1680
- typer.echo("Warning: remove_content_history is an experimental feature", err=True)
1681
- client.remove_content_history(page_id, version)
1682
- result_payload = {"page_id": page_id, "version": version, "status": "removed"}
1683
-
1684
- else:
1685
- raise typer.BadParameter(f"Unknown action: {action}")
1686
-
1687
- if json_output or not sys.stdout.isatty():
1688
- _emit_json(result_payload)
1689
- else:
1690
- typer.echo(json.dumps(result_payload, indent=2, sort_keys=True))
1691
-
1692
- except (VDSClientError, typer.BadParameter) as exc:
1693
- exit_code = 1
1694
- logger.exception("history_failed: %s", exc)
1695
- typer.echo(f"Error: {exc}", err=True)
1696
- except Exception as exc: # pragma: no cover - unexpected errors
1697
- exit_code = 1
1698
- logger.exception("history_unexpected_error")
1699
- typer.echo(f"Error: {exc}", err=True)
1700
- finally:
1701
- finished_at = datetime.now(UTC)
1702
- server_label = server_key or (server.lower() if server else "internal")
1703
- _record_summary(
1704
- parent_ctx,
1705
- command="history",
1706
- args=args_summary,
1707
- server=server_label,
1708
- exit_code=exit_code,
1709
- started_at=started_at,
1710
- finished_at=finished_at,
1711
- )
1712
- if exit_code != 0:
1713
- raise typer.Exit(code=exit_code) from None
1714
-
1715
-
1716
- @app.command("cache")
1717
- def cmd_cache(
1718
- ctx: typer.Context,
1719
- action: str = typer.Argument(..., help="Action: statistics, flush, size"),
1720
- cache_name: str | None = typer.Option(None, "--cache-name", help="Cache name (for flush)"),
1721
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
1722
- yes: bool = typer.Option(False, "--yes", help="Confirm write operation (for flush)"),
1723
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
1724
- ) -> None:
1725
- """Manage Confluence cache (Server-only)."""
1726
- parent_ctx = _parent_context(ctx)
1727
- started_at = datetime.now(UTC)
1728
- exit_code = 0
1729
- result_payload: dict[str, Any] = {}
1730
- args_summary: list[str] = []
1731
- server_key: str | None = None
1732
- settings: ConfluenceSettings | None = None
1733
-
1734
- try:
1735
- settings = load_settings(strict=True)
1736
- server_key = _normalise_server(server, settings)
1737
- client = _build_http_client(settings, server_key)
1738
-
1739
- args_summary = [action]
1740
-
1741
- if action == "statistics":
1742
- result = client.get_cache_statistics()
1743
- result_payload = {"cache_statistics": result}
1744
- elif action == "flush":
1745
- if not yes:
1746
- raise typer.BadParameter("Refusing to flush cache without --yes")
1747
- if cache_name:
1748
- args_summary.append(f"cache_name={cache_name}")
1749
- client.flush_cache(cache_name=cache_name)
1750
- result_payload = {"status": "success", "cache_flushed": cache_name or "all"}
1751
- elif action == "size":
1752
- result = client.get_cache_size()
1753
- result_payload = {"cache_size": result}
1754
- else:
1755
- raise typer.BadParameter(f"Unknown action: {action}")
1756
-
1757
- if json_output or not sys.stdout.isatty():
1758
- _emit_json(result_payload)
1759
- else:
1760
- typer.echo(json.dumps(result_payload, indent=2, sort_keys=True))
1761
-
1762
- except (VDSClientError, typer.BadParameter) as exc:
1763
- exit_code = 1
1764
- logger.exception("cache_failed: %s", exc)
1765
- typer.echo(f"Error: {exc}", err=True)
1766
- except Exception as exc: # pragma: no cover - unexpected errors
1767
- exit_code = 1
1768
- logger.exception("cache_unexpected_error")
1769
- typer.echo(f"Error: {exc}", err=True)
1770
- finally:
1771
- finished_at = datetime.now(UTC)
1772
- server_label = server_key or (server.lower() if server else "internal")
1773
- _record_summary(
1774
- parent_ctx,
1775
- command="cache",
1776
- args=args_summary,
1777
- server=server_label,
1778
- exit_code=exit_code,
1779
- started_at=started_at,
1780
- finished_at=finished_at,
1781
- )
1782
- if exit_code != 0:
1783
- raise typer.Exit(code=exit_code) from None
1784
-
1785
-
1786
- @app.command("get")
1787
- def cmd_get(
1788
- ctx: typer.Context,
1789
- page_id: str = typer.Argument(..., help="Confluence page ID"),
1790
- expand: str | None = typer.Option(
1791
- None, "--expand", "-e", help="Comma separated expansions (e.g., 'body.storage,version')"
1792
- ),
1793
- format: str | None = typer.Option(None, "--format", "-f", help="Output format (storage|editor|view)"),
1794
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
1795
- ) -> None:
1796
- """Get Confluence content by page ID."""
1797
- parent_ctx = _parent_context(ctx)
1798
- _ensure_v1_api(parent_ctx, "get")
1799
- started_at = datetime.now(UTC)
1800
- settings = load_settings(strict=True)
1801
- server_key = _normalise_server(server, settings)
1802
-
1803
- try:
1804
- client = ContentClientV2(_build_http_client(settings, server_key))
1805
- content = client.get_content(page_id, expand=_expand_option(expand), format=format)
1806
-
1807
- if content:
1808
- _emit_json(content)
1809
- else:
1810
- typer.echo(f"Content not found: {page_id}", err=True)
1811
- raise typer.Exit(code=1) from None
1812
-
1813
- finished_at = datetime.now(UTC)
1814
- _record_summary(
1815
- parent_ctx,
1816
- command="get",
1817
- args=[page_id],
1818
- server=server_key,
1819
- exit_code=0,
1820
- started_at=started_at,
1821
- finished_at=finished_at,
1822
- )
1823
-
1824
- except Exception as exc:
1825
- logger.exception("get_command_failed: %s", exc)
1826
- typer.echo(f"Error: {exc}", err=True)
1827
- raise typer.Exit(code=1) from None
1828
-
1829
-
1830
- # ---------------------------------------------------------------------------
1831
- # Native content commands
1832
- # ---------------------------------------------------------------------------
1833
-
1834
-
1835
- @batch_app.command("scan")
1836
- def batch_scan(
1837
- ctx: typer.Context,
1838
- cql: str = typer.Option(..., "--cql", "-q", help="CQL query string"),
1839
- limit: int = typer.Option(25, "--limit", help="Number of results per request"),
1840
- max_results: int | None = typer.Option(None, "--max-results", help="Total results to fetch"),
1841
- start: int = typer.Option(0, "--start", help="Pagination start offset"),
1842
- expand: str | None = typer.Option(None, "--expand", help="Comma separated expansions"),
1843
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
1844
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
1845
- ) -> None:
1846
- parent_ctx = _parent_context(ctx)
1847
- _ensure_v1_api(parent_ctx, "batch.scan")
1848
- started_at = datetime.now(UTC)
1849
- settings = load_settings(strict=True)
1850
- server_key = _normalise_server(server, settings)
1851
- runner = BatchRunner(_build_http_client(settings, server_key), expand=_expand_option(expand))
1852
- results: list[dict[str, Any]] = []
1853
- for item in runner.scan(cql, limit=limit, max_results=max_results, start=start):
1854
- results.append(item)
1855
- metrics = runner.last_metrics
1856
- payload: dict[str, Any] = {
1857
- "cql": cql,
1858
- "count": len(results),
1859
- "limit": limit,
1860
- "maxResults": max_results,
1861
- "start": start,
1862
- "results": results,
1863
- }
1864
- if metrics is not None:
1865
- payload["metrics"] = {
1866
- "requests": metrics.requests,
1867
- "pagesProcessed": metrics.pages_processed,
1868
- "durationSeconds": metrics.duration_seconds,
1869
- }
1870
- if json_output or not sys.stdout.isatty():
1871
- _emit_json(payload)
1872
- else:
1873
- typer.echo(
1874
- f"Scanned {payload['count']} results (requests={payload['metrics']['requests'] if 'metrics' in payload else '?'})"
1875
- )
1876
- finished_at = datetime.now(UTC)
1877
- _record_summary(
1878
- parent_ctx,
1879
- command="batch.scan",
1880
- args=[cql, f"limit={limit}", f"start={start}"],
1881
- server=server_key,
1882
- exit_code=0,
1883
- started_at=started_at,
1884
- finished_at=finished_at,
1885
- )
1886
-
1887
-
1888
- @batch_app.command("snapshot")
1889
- def batch_snapshot(
1890
- ctx: typer.Context,
1891
- cql: str = typer.Option(..., "--cql", "-q", help="CQL query string"),
1892
- limit: int = typer.Option(25, "--limit", help="Number of results per request"),
1893
- max_results: int | None = typer.Option(None, "--max-results", help="Total results to fetch"),
1894
- expand: str | None = typer.Option(None, "--expand", help="Comma separated expansions"),
1895
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
1896
- ) -> None:
1897
- parent_ctx = _parent_context(ctx)
1898
- _ensure_v1_api(parent_ctx, "batch.snapshot")
1899
- started_at = datetime.now(UTC)
1900
- settings = load_settings(strict=True)
1901
- server_key = _normalise_server(server, settings)
1902
- runner = BatchRunner(_build_http_client(settings, server_key))
1903
- payload = runner.snapshot(cql, limit=limit, max_results=max_results, expand=_expand_option(expand))
1904
- _emit_json(payload)
1905
- finished_at = datetime.now(UTC)
1906
- _record_summary(
1907
- parent_ctx,
1908
- command="batch.snapshot",
1909
- args=[cql, f"limit={limit}"],
1910
- server=server_key,
1911
- exit_code=0,
1912
- started_at=started_at,
1913
- finished_at=finished_at,
1914
- )
1915
-
1916
-
1917
- @batch_app.command("poll")
1918
- def batch_poll(
1919
- ctx: typer.Context,
1920
- cql: str = typer.Option(..., "--cql", "-q", help="Base CQL query (will be augmented with lastmodified filter)"),
1921
- state_file: Path = typer.Option(..., "--state-file", help="Path to persistent cursor file (JSON)"),
1922
- limit: int = typer.Option(25, "--limit", help="Page size per request"),
1923
- max_results: int | None = typer.Option(None, "--max-results", help="Max results this run"),
1924
- expand: str | None = typer.Option(
1925
- "version", "--expand", help="Comma separated expansions (default includes 'version')"
1926
- ),
1927
- out_jsonl: Path | None = typer.Option(None, "--out-jsonl", help="Write results to JSONL (one object per line)"),
1928
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
1929
- ) -> None:
1930
- parent_ctx = _parent_context(ctx)
1931
- _ensure_v1_api(parent_ctx, "batch.poll")
1932
- started_at = datetime.now(UTC)
1933
- server_key = "internal"
1934
- try:
1935
- settings = load_settings(strict=True)
1936
- server_key = _normalise_server(server, settings)
1937
- client = _build_http_client(settings, server_key)
1938
- poller = Poller(client)
1939
- expand_list = _expand_option(expand) or ["version"]
1940
- count = poller.poll_once(
1941
- base_cql=cql,
1942
- state_file=state_file,
1943
- limit=limit,
1944
- max_results=max_results,
1945
- expand=expand_list,
1946
- out_jsonl=out_jsonl,
1947
- )
1948
- typer.echo(f"Polled {count} items")
1949
- except Exception as exc:
1950
- logger.exception("batch.poll failed", extra={"cql": cql})
1951
- typer.echo(f"Error: {exc}", err=True)
1952
- raise typer.Exit(code=1) from None
1953
- finally:
1954
- finished_at = datetime.now(UTC)
1955
- _record_summary(
1956
- parent_ctx,
1957
- command="batch.poll",
1958
- args=[cql, f"limit={limit}", f"out={str(out_jsonl) if out_jsonl else '-'}"],
1959
- server=server_key,
1960
- exit_code=0,
1961
- started_at=started_at,
1962
- finished_at=finished_at,
1963
- )
1964
-
1965
-
1966
- @webhook_app.command("create")
1967
- def webhook_create(
1968
- ctx: typer.Context,
1969
- name: str = typer.Option(..., "--name", "-n", help="Webhook name"),
1970
- url: str = typer.Option(..., "--url", help="Destination URL"),
1971
- event: list[str] = typer.Option(["page_created"], "--event", "-e", help="Event identifier"),
1972
- active: bool = typer.Option(True, "--active/--inactive", help="Toggle webhook activation"),
1973
- filters: str | None = typer.Option(None, "--filters", help="JSON object filters"),
1974
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
1975
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
1976
- ) -> None:
1977
- parent_ctx = _parent_context(ctx)
1978
- _ensure_v1_api(parent_ctx, "webhook.create")
1979
- started_at = datetime.now(UTC)
1980
- settings = load_settings(strict=True)
1981
- server_key = _normalise_server(server, settings)
1982
- client = WebhookClient(_build_http_client(settings, server_key))
1983
- payload = client.create(
1984
- name=name,
1985
- url=url,
1986
- events=event,
1987
- active=active,
1988
- filters=_parse_json_option(filters, "--filters"),
1989
- )
1990
- if json_output:
1991
- _emit_json(payload)
1992
- else:
1993
- typer.echo(f"Created webhook {payload.get('id')}")
1994
- finished_at = datetime.now(UTC)
1995
- _record_summary(
1996
- parent_ctx,
1997
- command="webhook.create",
1998
- args=[name, f"events={len(event)}"],
1999
- server=server_key,
2000
- exit_code=0,
2001
- started_at=started_at,
2002
- finished_at=finished_at,
2003
- )
2004
-
2005
-
2006
- @webhook_app.command("list")
2007
- def webhook_list(
2008
- ctx: typer.Context,
2009
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2010
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
2011
- ) -> None:
2012
- parent_ctx = _parent_context(ctx)
2013
- _ensure_v1_api(parent_ctx, "webhook.list")
2014
- started_at = datetime.now(UTC)
2015
- settings = load_settings(strict=True)
2016
- server_key = _normalise_server(server, settings)
2017
- client = WebhookClient(_build_http_client(settings, server_key))
2018
- payload = client.list()
2019
- if json_output:
2020
- _emit_json(payload)
2021
- else:
2022
- typer.echo(f"{len(payload)} webhooks")
2023
- finished_at = datetime.now(UTC)
2024
- _record_summary(
2025
- parent_ctx,
2026
- command="webhook.list",
2027
- args=[f"count={len(payload)}"],
2028
- server=server_key,
2029
- exit_code=0,
2030
- started_at=started_at,
2031
- finished_at=finished_at,
2032
- )
2033
-
2034
-
2035
- @webhook_app.command("delete")
2036
- def webhook_delete(
2037
- ctx: typer.Context,
2038
- webhook_id: str = typer.Argument(..., help="Webhook identifier"),
2039
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2040
- ) -> None:
2041
- parent_ctx = _parent_context(ctx)
2042
- _ensure_v1_api(parent_ctx, "webhook.delete")
2043
- started_at = datetime.now(UTC)
2044
- settings = load_settings(strict=True)
2045
- server_key = _normalise_server(server, settings)
2046
- client = WebhookClient(_build_http_client(settings, server_key))
2047
- client.delete(webhook_id)
2048
- typer.echo(f"Deleted webhook {webhook_id}")
2049
- finished_at = datetime.now(UTC)
2050
- _record_summary(
2051
- parent_ctx,
2052
- command="webhook.delete",
2053
- args=[webhook_id],
2054
- server=server_key,
2055
- exit_code=0,
2056
- started_at=started_at,
2057
- finished_at=finished_at,
2058
- )
2059
-
2060
-
2061
- @content_app.command("page")
2062
- def content_page(
2063
- ctx: typer.Context,
2064
- page_id: str = typer.Argument(..., help="Confluence page ID"),
2065
- expand: str | None = typer.Option(None, "--expand", help="Comma separated expansions"),
2066
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2067
- ) -> None:
2068
- """Fetch a Confluence page by ID."""
2069
- parent_ctx = _parent_context(ctx)
2070
- started_at = datetime.now(UTC)
2071
- try:
2072
- settings = load_settings(strict=True)
2073
- server_key = _normalise_server(server, settings)
2074
- cli_ctx = _get_cli_ctx(parent_ctx)
2075
- client = _build_content_client(settings, server_key, cli_ctx.api_version)
2076
- expand_list = _expand_option(expand)
2077
- payload = client.get_page(page_id, expand=expand_list)
2078
- _emit_json(payload)
2079
- except Exception as exc:
2080
- logger.exception("content.page failed", extra={"page_id": page_id})
2081
- typer.echo(f"Error: {exc}", err=True)
2082
- raise typer.Exit(code=1) from None
2083
- else:
2084
- finished_at = datetime.now(UTC)
2085
- _record_summary(
2086
- parent_ctx,
2087
- command="content.page",
2088
- args=[page_id],
2089
- server=server_key,
2090
- exit_code=0,
2091
- started_at=started_at,
2092
- finished_at=finished_at,
2093
- )
2094
-
2095
-
2096
- @content_app.command("search")
2097
- def content_search(
2098
- ctx: typer.Context,
2099
- cql: str = typer.Argument(..., help="CQL query string"),
2100
- limit: int = typer.Option(25, "--limit", help="Number of results"),
2101
- start: int = typer.Option(0, "--start", help="Pagination start"),
2102
- expand: str | None = typer.Option(None, "--expand", help="Comma separated expansions"),
2103
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2104
- ) -> None:
2105
- """Search Confluence pages by CQL query."""
2106
- parent_ctx = _parent_context(ctx)
2107
- started_at = datetime.now(UTC)
2108
- exit_code = 0
2109
- server_key: str = ""
2110
- try:
2111
- settings = load_settings(strict=True)
2112
- server_key = _normalise_server(server, settings)
2113
- cli_ctx = _get_cli_ctx(parent_ctx)
2114
- client = _build_content_client(settings, server_key, cli_ctx.api_version)
2115
- expand_list = _expand_option(expand)
2116
- payload = client.search_cql(cql, limit=limit, start=start, expand=expand_list)
2117
- _emit_json(payload)
2118
- except Exception as exc:
2119
- exit_code = 1
2120
- logger.exception("content.search failed", extra={"cql": cql})
2121
- # Provide targeted guidance for CQL auth failures
2122
- from .errors import AuthError # local import to avoid top-level cycles
2123
-
2124
- if isinstance(exc, AuthError):
2125
- typer.echo("Error: Authentication failed for CQL search.", err=True)
2126
- typer.echo("Hint: We default to Basic auth (VDS_USERNAME/PASSWORD). If using token, ensure:", err=True)
2127
- typer.echo(" - Token has permission to use CQL (/rest/api/*search)", err=True)
2128
- typer.echo(" - Or set VDS_USERNAME/VDS_PASSWORD to use Basic auth", err=True)
2129
- typer.echo(
2130
- " - Quick check: curl -u \"$VDS_USERNAME:$VDS_PASSWORD\" 'http://confluence.digital.vn/rest/api/search?cql=type=page&limit=1'",
2131
- err=True,
2132
- )
2133
- else:
2134
- typer.echo(f"Error: {exc}", err=True)
2135
- finally:
2136
- finished_at = datetime.now(UTC)
2137
- _record_summary(
2138
- parent_ctx,
2139
- command="content.search",
2140
- args=_content_summary_args(cql=cql, limit=limit, start=start),
2141
- server=server_key,
2142
- exit_code=exit_code,
2143
- started_at=started_at,
2144
- finished_at=finished_at,
2145
- )
2146
- if exit_code != 0:
2147
- raise typer.Exit(code=exit_code) from None
2148
-
2149
-
2150
- @content_app.command("templates")
2151
- def content_templates(
2152
- ctx: typer.Context,
2153
- space_key: str | None = typer.Option(None, "--space", help="Space key"),
2154
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2155
- ) -> None:
2156
- """List available Confluence page templates."""
2157
- parent_ctx = _parent_context(ctx)
2158
- started_at = datetime.now(UTC)
2159
- try:
2160
- settings = load_settings(strict=True)
2161
- server_key = _normalise_server(server, settings)
2162
- cli_ctx = _get_cli_ctx(parent_ctx)
2163
- client = _build_content_client(settings, server_key, cli_ctx.api_version)
2164
- if hasattr(client, "list_templates"):
2165
- payload = client.list_templates(space_key=space_key)
2166
- else:
2167
- payload = {"templates": [], "message": "Templates API not available for this server"}
2168
- _emit_json(payload)
2169
- except Exception as exc:
2170
- logger.exception("content.templates failed", extra={"space": space_key})
2171
- typer.echo(f"Error: {exc}", err=True)
2172
- raise typer.Exit(code=1) from None
2173
- else:
2174
- finished_at = datetime.now(UTC)
2175
- _record_summary(
2176
- parent_ctx,
2177
- command="content.templates",
2178
- args=_content_summary_args(space=space_key or "*"),
2179
- server=server_key,
2180
- exit_code=0,
2181
- started_at=started_at,
2182
- finished_at=finished_at,
2183
- )
2184
-
2185
-
2186
- @content_app.command("create-page")
2187
- def content_create_page(
2188
- ctx: typer.Context,
2189
- space_key: str = typer.Option(..., "--space", "-S", help="Space key to create the page in"),
2190
- title: str = typer.Option(..., "--title", "-t", help="Page title"),
2191
- body_file: Path = typer.Option(
2192
- ..., "--body-file", exists=True, file_okay=True, dir_okay=False, help="Path to storage-format body"
2193
- ),
2194
- parent_id: str | None = typer.Option(None, "--parent", help="Ancestor page id"),
2195
- representation: str = typer.Option(
2196
- "storage", "--representation", help="Content representation (storage, wiki, view)"
2197
- ),
2198
- status: str = typer.Option("current", "--status", help="Target page status (current, draft)"),
2199
- notify_watchers: bool = typer.Option(
2200
- False, "--notify-watchers/--no-notify-watchers", help="Send notifications to watchers"
2201
- ),
2202
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2203
- ) -> None:
2204
- """Create a new Confluence page."""
2205
- parent_ctx = _parent_context(ctx)
2206
- _ensure_v1_api(parent_ctx, "content.create-page")
2207
- started_at = datetime.now(UTC)
2208
- try:
2209
- settings = load_settings(strict=True)
2210
- server_key = _normalise_server(server, settings)
2211
- client = ContentClient(_build_http_client(settings, server_key))
2212
- body = _read_text_file(body_file)
2213
- payload = client.create_page(
2214
- space_key=space_key,
2215
- title=title,
2216
- body=body,
2217
- parent_id=parent_id,
2218
- representation=representation,
2219
- status=status,
2220
- notify_watchers=notify_watchers,
2221
- )
2222
- _emit_json(payload)
2223
- except Exception as exc:
2224
- logger.exception("content.create-page failed", extra={"space": space_key, "title": title})
2225
- typer.echo(f"Error: {exc}", err=True)
2226
- raise typer.Exit(code=1) from None
2227
- else:
2228
- finished_at = datetime.now(UTC)
2229
- _record_summary(
2230
- parent_ctx,
2231
- command="content.create-page",
2232
- args=[f"space={space_key}", f"title={title}"],
2233
- server=server_key,
2234
- exit_code=0,
2235
- started_at=started_at,
2236
- finished_at=finished_at,
2237
- )
2238
-
2239
-
2240
- @content_app.command("update-page")
2241
- def content_update_page(
2242
- ctx: typer.Context,
2243
- page_id: str = typer.Argument(..., help="Confluence page ID"),
2244
- title: str | None = typer.Option(None, "--title", help="New page title"),
2245
- body_file: Path | None = typer.Option(
2246
- None, "--body-file", exists=True, file_okay=True, dir_okay=False, help="Path to storage-format body"
2247
- ),
2248
- space_key: str | None = typer.Option(None, "--space", help="Move page to this space"),
2249
- version: int | None = typer.Option(None, "--version", help="Explicit version number"),
2250
- representation: str = typer.Option("storage", "--representation", help="Content representation for --body-file"),
2251
- minor_edit: bool = typer.Option(False, "--minor-edit/--no-minor-edit", help="Mark version as minor edit"),
2252
- message: str | None = typer.Option(None, "--message", help="Version comment"),
2253
- status: str = typer.Option("current", "--status", help="Target page status"),
2254
- notify_watchers: bool = typer.Option(
2255
- False, "--notify-watchers/--no-notify-watchers", help="Send notifications to watchers"
2256
- ),
2257
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2258
- ) -> None:
2259
- """Update an existing Confluence page."""
2260
- parent_ctx = _parent_context(ctx)
2261
- _ensure_v1_api(parent_ctx, "content.update-page")
2262
- if body_file is None and title is None and space_key is None:
2263
- raise typer.BadParameter("Provide at least one of --title, --body-file or --space")
2264
- body = _read_text_file(body_file) if body_file else None
2265
- started_at = datetime.now(UTC)
2266
- try:
2267
- settings = load_settings(strict=True)
2268
- server_key = _normalise_server(server, settings)
2269
- client = ContentClient(_build_http_client(settings, server_key))
2270
- payload = client.update_page(
2271
- page_id,
2272
- title=title,
2273
- body=body,
2274
- space_key=space_key,
2275
- representation=representation,
2276
- version=version,
2277
- minor_edit=minor_edit,
2278
- message=message,
2279
- status=status,
2280
- notify_watchers=notify_watchers,
2281
- )
2282
- _emit_json(payload)
2283
- except Exception as exc:
2284
- logger.exception("content.update-page failed", extra={"page_id": page_id})
2285
- typer.echo(f"Error: {exc}", err=True)
2286
- raise typer.Exit(code=1) from None
2287
- else:
2288
- finished_at = datetime.now(UTC)
2289
- args = [page_id]
2290
- if version is not None:
2291
- args.append(f"version={version}")
2292
- if title is not None:
2293
- args.append(f"title={title}")
2294
- _record_summary(
2295
- parent_ctx,
2296
- command="content.update-page",
2297
- args=args,
2298
- server=server_key,
2299
- exit_code=0,
2300
- started_at=started_at,
2301
- finished_at=finished_at,
2302
- )
2303
-
2304
-
2305
- @content_app.command("delete-page")
2306
- def content_delete_page(
2307
- ctx: typer.Context,
2308
- page_id: str = typer.Argument(..., help="Confluence page ID"),
2309
- status: str = typer.Option("current", "--status", help="Specify current or draft"),
2310
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2311
- ) -> None:
2312
- """Delete a Confluence page."""
2313
- parent_ctx = _parent_context(ctx)
2314
- _ensure_v1_api(parent_ctx, "content.delete-page")
2315
- started_at = datetime.now(UTC)
2316
- try:
2317
- settings = load_settings(strict=True)
2318
- server_key = _normalise_server(server, settings)
2319
- client = ContentClient(_build_http_client(settings, server_key))
2320
- client.delete_page(page_id, status=status)
2321
- typer.echo(f"Deleted page {page_id} (status={status})")
2322
- except Exception as exc:
2323
- logger.exception("content.delete-page failed", extra={"page_id": page_id})
2324
- typer.echo(f"Error: {exc}", err=True)
2325
- raise typer.Exit(code=1) from None
2326
- else:
2327
- finished_at = datetime.now(UTC)
2328
- _record_summary(
2329
- parent_ctx,
2330
- command="content.delete-page",
2331
- args=[page_id, f"status={status}"],
2332
- server=server_key,
2333
- exit_code=0,
2334
- started_at=started_at,
2335
- finished_at=finished_at,
2336
- )
2337
-
2338
-
2339
- @content_app.command("add-attachment")
2340
- def content_add_attachment(
2341
- ctx: typer.Context,
2342
- page_id: str = typer.Argument(..., help="Confluence page ID"),
2343
- file_path: Path = typer.Option(..., "--file", exists=True, file_okay=True, dir_okay=False, help="File to upload"),
2344
- filename: str | None = typer.Option(None, "--filename", help="Override uploaded filename"),
2345
- content_type: str | None = typer.Option(None, "--content-type", help="MIME type for the attachment"),
2346
- comment: str | None = typer.Option(None, "--comment", help="Attachment comment"),
2347
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2348
- ) -> None:
2349
- """Add an attachment to a Confluence page."""
2350
- parent_ctx = _parent_context(ctx)
2351
- _ensure_v1_api(parent_ctx, "content.add-attachment")
2352
- started_at = datetime.now(UTC)
2353
- try:
2354
- settings = load_settings(strict=True)
2355
- server_key = _normalise_server(server, settings)
2356
- client = ContentClient(_build_http_client(settings, server_key))
2357
- payload = client.upload_attachment(
2358
- page_id,
2359
- str(file_path),
2360
- filename=filename,
2361
- content_type=content_type,
2362
- comment=comment,
2363
- )
2364
- _emit_json(payload)
2365
- except Exception as exc:
2366
- logger.exception("content.add-attachment failed", extra={"page_id": page_id, "file": str(file_path)})
2367
- typer.echo(f"Error: {exc}", err=True)
2368
- raise typer.Exit(code=1) from None
2369
- else:
2370
- finished_at = datetime.now(UTC)
2371
- _record_summary(
2372
- parent_ctx,
2373
- command="content.add-attachment",
2374
- args=[page_id, file_path.name],
2375
- server=server_key,
2376
- exit_code=0,
2377
- started_at=started_at,
2378
- finished_at=finished_at,
2379
- )
2380
-
2381
-
2382
- @content_app.command("download-attachment")
2383
- def content_download_attachment(
2384
- ctx: typer.Context,
2385
- attachment_id: str = typer.Argument(..., help="Attachment ID"),
2386
- output_path: Path = typer.Option(
2387
- ..., "--out", "-o", file_okay=True, dir_okay=True, help="Output file path or directory"
2388
- ),
2389
- filename: str | None = typer.Option(None, "--filename", help="Override downloaded filename"),
2390
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2391
- ) -> None:
2392
- """Download a Confluence attachment by ID to a local file."""
2393
- parent_ctx = _parent_context(ctx)
2394
- _ensure_v1_api(parent_ctx, "content.download-attachment")
2395
- started_at = datetime.now(UTC)
2396
- try:
2397
- settings = load_settings(strict=True)
2398
- server_key = _normalise_server(server, settings)
2399
- client = ContentClient(_build_http_client(settings, server_key))
2400
- output = client.download_attachment(attachment_id, output_path, filename=filename)
2401
- _emit_json({"attachment_id": attachment_id, "output_path": str(output)})
2402
- except Exception as exc:
2403
- logger.exception("content.download-attachment failed", extra={"attachment_id": attachment_id})
2404
- typer.echo(f"Error: {exc}", err=True)
2405
- raise typer.Exit(code=1) from None
2406
- else:
2407
- finished_at = datetime.now(UTC)
2408
- _record_summary(
2409
- parent_ctx,
2410
- command="content.download-attachment",
2411
- args=[attachment_id, str(output_path)],
2412
- server=server_key,
2413
- exit_code=0,
2414
- started_at=started_at,
2415
- finished_at=finished_at,
2416
- )
2417
-
2418
-
2419
- @content_app.command("add-comment")
2420
- def content_add_comment(
2421
- ctx: typer.Context,
2422
- page_id: str = typer.Argument(..., help="Confluence page ID"),
2423
- body: str | None = typer.Option(None, "--body", help="Comment body in Confluence storage format"),
2424
- body_file: Path | None = typer.Option(
2425
- None, "--body-file", exists=True, file_okay=True, dir_okay=False, help="Path to file containing comment body"
2426
- ),
2427
- parent_id: str | None = typer.Option(
2428
- None,
2429
- "--parent-id",
2430
- help="Optional parent comment ID to create a threaded reply instead of a top-level comment",
2431
- ),
2432
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2433
- ) -> None:
2434
- """Add a comment to a Confluence page."""
2435
- parent_ctx = _parent_context(ctx)
2436
- _ensure_v1_api(parent_ctx, "content.add-comment")
2437
- started_at = datetime.now(UTC)
2438
-
2439
- if bool(body) == bool(body_file):
2440
- raise typer.BadParameter("Provide either --body or --body-file")
2441
-
2442
- try:
2443
- settings = load_settings(strict=True)
2444
- server_key = _normalise_server(server, settings)
2445
- client = ContentClient(_build_http_client(settings, server_key))
2446
- if body is not None:
2447
- comment_body = body
2448
- else:
2449
- assert body_file is not None
2450
- comment_body = _read_text_file(body_file)
2451
- payload = client.add_comment(page_id, comment_body, parent_id=parent_id)
2452
- _emit_json(payload)
2453
- except Exception as exc:
2454
- logger.exception("content.add-comment failed", extra={"page_id": page_id})
2455
- typer.echo(f"Error: {exc}", err=True)
2456
- raise typer.Exit(code=1) from None
2457
- else:
2458
- finished_at = datetime.now(UTC)
2459
- _record_summary(
2460
- parent_ctx,
2461
- command="content.add-comment",
2462
- args=[page_id],
2463
- server=server_key,
2464
- exit_code=0,
2465
- started_at=started_at,
2466
- finished_at=finished_at,
2467
- )
2468
-
2469
-
2470
- @content_app.command("update-attachment")
2471
- def content_update_attachment(
2472
- ctx: typer.Context,
2473
- page_id: str = typer.Argument(..., help="Confluence page ID"),
2474
- attachment_id: str = typer.Argument(..., help="Attachment ID"),
2475
- file_path: Path = typer.Option(..., "--file", exists=True, file_okay=True, dir_okay=False, help="Replacement file"),
2476
- filename: str | None = typer.Option(None, "--filename", help="Override uploaded filename"),
2477
- content_type: str | None = typer.Option(None, "--content-type", help="MIME type for the attachment"),
2478
- comment: str | None = typer.Option(None, "--comment", help="Attachment comment"),
2479
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2480
- ) -> None:
2481
- """Update an existing attachment on a Confluence page."""
2482
- parent_ctx = _parent_context(ctx)
2483
- _ensure_v1_api(parent_ctx, "content.update-attachment")
2484
- started_at = datetime.now(UTC)
2485
- try:
2486
- settings = load_settings(strict=True)
2487
- server_key = _normalise_server(server, settings)
2488
- client = ContentClient(_build_http_client(settings, server_key))
2489
- payload = client.update_attachment(
2490
- page_id,
2491
- attachment_id,
2492
- str(file_path),
2493
- filename=filename,
2494
- content_type=content_type,
2495
- comment=comment,
2496
- )
2497
- _emit_json(payload)
2498
- except Exception as exc:
2499
- logger.exception("content.update-attachment failed", extra={"page_id": page_id, "attachment_id": attachment_id})
2500
- typer.echo(f"Error: {exc}", err=True)
2501
- raise typer.Exit(code=1) from None
2502
- else:
2503
- finished_at = datetime.now(UTC)
2504
- _record_summary(
2505
- parent_ctx,
2506
- command="content.update-attachment",
2507
- args=[page_id, attachment_id],
2508
- server=server_key,
2509
- exit_code=0,
2510
- started_at=started_at,
2511
- finished_at=finished_at,
2512
- )
2513
-
2514
-
2515
- @content_app.command("delete-attachment")
2516
- def content_delete_attachment(
2517
- ctx: typer.Context,
2518
- page_id: str = typer.Argument(..., help="Confluence page ID"),
2519
- attachment_id: str | None = typer.Argument(None, help="Attachment ID"),
2520
- version: int | None = typer.Option(None, "--version", help="Delete a specific attachment version"),
2521
- filename: str | None = typer.Option(None, "--filename", help="Attachment filename (delete all versions)"),
2522
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2523
- ) -> None:
2524
- """Delete an attachment from a Confluence page."""
2525
- parent_ctx = _parent_context(ctx)
2526
- _ensure_v1_api(parent_ctx, "content.delete-attachment")
2527
- started_at = datetime.now(UTC)
2528
- try:
2529
- settings = load_settings(strict=True)
2530
- server_key = _normalise_server(server, settings)
2531
- if not attachment_id and not filename:
2532
- raise typer.BadParameter("Provide either attachment_id or --filename")
2533
-
2534
- client = ContentClient(_build_http_client(settings, server_key))
2535
- client.delete_attachment(page_id, attachment_id=attachment_id, version=version, filename=filename)
2536
- target = filename or attachment_id
2537
- typer.echo(f"Deleted attachment {target} from page {page_id}")
2538
- except Exception as exc:
2539
- logger.exception("content.delete-attachment failed", extra={"page_id": page_id, "attachment_id": attachment_id})
2540
- typer.echo(f"Error: {exc}", err=True)
2541
- raise typer.Exit(code=1) from None
2542
- else:
2543
- finished_at = datetime.now(UTC)
2544
- _record_summary(
2545
- parent_ctx,
2546
- command="content.delete-attachment",
2547
- args=[
2548
- page_id,
2549
- filename or attachment_id or "<unspecified>",
2550
- f"version={version}" if version is not None else "all_versions",
2551
- ],
2552
- server=server_key,
2553
- exit_code=0,
2554
- started_at=started_at,
2555
- finished_at=finished_at,
2556
- )
2557
-
2558
-
2559
- @content_app.command("ancestors")
2560
- def content_ancestors(
2561
- ctx: typer.Context,
2562
- page_id: str = typer.Argument(..., help="Confluence page ID"),
2563
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2564
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
2565
- ) -> None:
2566
- """Get page ancestors (parent pages)."""
2567
- parent_ctx = _parent_context(ctx)
2568
- started_at = datetime.now(UTC)
2569
- exit_code = 0
2570
- result_payload: dict[str, Any] = {}
2571
- server_key: str | None = None
2572
-
2573
- try:
2574
- settings = load_settings(strict=True)
2575
- server_key = _normalise_server(server, settings)
2576
- client = _build_http_client(settings, server_key)
2577
-
2578
- result = client.get_page_ancestors(page_id)
2579
- result_payload = {"page_id": page_id, "count": len(result), "ancestors": result}
2580
-
2581
- if json_output or not sys.stdout.isatty():
2582
- _emit_json(result_payload)
2583
- else:
2584
- typer.echo(json.dumps(result_payload, indent=2, sort_keys=True))
2585
-
2586
- except (VDSClientError, typer.BadParameter) as exc:
2587
- exit_code = 1
2588
- logger.exception("content.ancestors_failed: %s", exc)
2589
- typer.echo(f"Error: {exc}", err=True)
2590
- except Exception as exc: # pragma: no cover - unexpected errors
2591
- exit_code = 1
2592
- logger.exception("content.ancestors_unexpected_error")
2593
- typer.echo(f"Error: {exc}", err=True)
2594
- finally:
2595
- finished_at = datetime.now(UTC)
2596
- server_label = server_key or (server.lower() if server else "internal")
2597
- _record_summary(
2598
- parent_ctx,
2599
- command="content.ancestors",
2600
- args=[page_id],
2601
- server=server_label,
2602
- exit_code=exit_code,
2603
- started_at=started_at,
2604
- finished_at=finished_at,
2605
- )
2606
- if exit_code != 0:
2607
- raise typer.Exit(code=exit_code) from None
2608
-
2609
-
2610
- @content_app.command("move")
2611
- def content_move(
2612
- ctx: typer.Context,
2613
- page_id: str = typer.Argument(..., help="Confluence page ID"),
2614
- target_title: str = typer.Option(..., "--target-title", help="Target page title to move under"),
2615
- position: str = typer.Option("append", "--position", help="Position: append, before, after"),
2616
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2617
- yes: bool = typer.Option(False, "--yes", help="Confirm move operation"),
2618
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
2619
- ) -> None:
2620
- """Move page to a new location."""
2621
- parent_ctx = _parent_context(ctx)
2622
- started_at = datetime.now(UTC)
2623
- exit_code = 0
2624
- result_payload: dict[str, Any] = {}
2625
- server_key: str | None = None
2626
-
2627
- try:
2628
- if not yes:
2629
- raise typer.BadParameter("--yes required for move operation")
2630
- if position not in ("append", "before", "after"):
2631
- raise typer.BadParameter("--position must be one of: append, before, after")
2632
-
2633
- settings = load_settings(strict=True)
2634
- server_key = _normalise_server(server, settings)
2635
- client = _build_http_client(settings, server_key)
2636
-
2637
- result = client.move_page(page_id, target_title, position=position)
2638
- result_payload = {"page_id": page_id, "target_title": target_title, "position": position, "result": result}
2639
-
2640
- if json_output or not sys.stdout.isatty():
2641
- _emit_json(result_payload)
2642
- else:
2643
- typer.echo(json.dumps(result_payload, indent=2, sort_keys=True))
2644
-
2645
- except (VDSClientError, typer.BadParameter) as exc:
2646
- exit_code = 1
2647
- logger.exception("content.move_failed: %s", exc)
2648
- typer.echo(f"Error: {exc}", err=True)
2649
- except Exception as exc: # pragma: no cover - unexpected errors
2650
- exit_code = 1
2651
- logger.exception("content.move_unexpected_error")
2652
- typer.echo(f"Error: {exc}", err=True)
2653
- finally:
2654
- finished_at = datetime.now(UTC)
2655
- server_label = server_key or (server.lower() if server else "internal")
2656
- _record_summary(
2657
- parent_ctx,
2658
- command="content.move",
2659
- args=[page_id, f"target={target_title}", f"position={position}"],
2660
- server=server_label,
2661
- exit_code=exit_code,
2662
- started_at=started_at,
2663
- finished_at=finished_at,
2664
- )
2665
- if exit_code != 0:
2666
- raise typer.Exit(code=exit_code) from None
2667
-
2668
-
2669
- @content_app.command("tables")
2670
- def content_tables(
2671
- ctx: typer.Context,
2672
- page_id: str = typer.Argument(..., help="Confluence page ID"),
2673
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2674
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
2675
- ) -> None:
2676
- """Extract tables from page."""
2677
- parent_ctx = _parent_context(ctx)
2678
- started_at = datetime.now(UTC)
2679
- exit_code = 0
2680
- result_payload: dict[str, Any] = {}
2681
- server_key: str | None = None
2682
-
2683
- try:
2684
- settings = load_settings(strict=True)
2685
- server_key = _normalise_server(server, settings)
2686
- client = _build_http_client(settings, server_key)
2687
-
2688
- result = client.get_tables_from_page(page_id)
2689
- result_payload = {"page_id": page_id, "count": len(result), "tables": result}
2690
-
2691
- if json_output or not sys.stdout.isatty():
2692
- _emit_json(result_payload)
2693
- else:
2694
- typer.echo(json.dumps(result_payload, indent=2, sort_keys=True))
2695
-
2696
- except (VDSClientError, typer.BadParameter) as exc:
2697
- exit_code = 1
2698
- logger.exception("content.tables_failed: %s", exc)
2699
- typer.echo(f"Error: {exc}", err=True)
2700
- except Exception as exc: # pragma: no cover - unexpected errors
2701
- exit_code = 1
2702
- logger.exception("content.tables_unexpected_error")
2703
- typer.echo(f"Error: {exc}", err=True)
2704
- finally:
2705
- finished_at = datetime.now(UTC)
2706
- server_label = server_key or (server.lower() if server else "internal")
2707
- _record_summary(
2708
- parent_ctx,
2709
- command="content.tables",
2710
- args=[page_id],
2711
- server=server_label,
2712
- exit_code=exit_code,
2713
- started_at=started_at,
2714
- finished_at=finished_at,
2715
- )
2716
- if exit_code != 0:
2717
- raise typer.Exit(code=exit_code) from None
2718
-
2719
-
2720
- @content_app.command("regex")
2721
- def content_regex(
2722
- ctx: typer.Context,
2723
- page_id: str = typer.Argument(..., help="Confluence page ID"),
2724
- pattern: str = typer.Option(..., "--pattern", help="Regex pattern to match"),
2725
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2726
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
2727
- ) -> None:
2728
- """Extract regex matches from page."""
2729
- parent_ctx = _parent_context(ctx)
2730
- started_at = datetime.now(UTC)
2731
- exit_code = 0
2732
- result_payload: dict[str, Any] = {}
2733
- server_key: str | None = None
2734
-
2735
- try:
2736
- settings = load_settings(strict=True)
2737
- server_key = _normalise_server(server, settings)
2738
- client = _build_http_client(settings, server_key)
2739
-
2740
- result = client.scrap_regex_from_page(page_id, pattern)
2741
- result_payload = {"page_id": page_id, "pattern": pattern, "count": len(result), "matches": result}
2742
-
2743
- if json_output or not sys.stdout.isatty():
2744
- _emit_json(result_payload)
2745
- else:
2746
- typer.echo(json.dumps(result_payload, indent=2, sort_keys=True))
2747
-
2748
- except (VDSClientError, typer.BadParameter) as exc:
2749
- exit_code = 1
2750
- logger.exception("content.regex_failed: %s", exc)
2751
- typer.echo(f"Error: {exc}", err=True)
2752
- except Exception as exc: # pragma: no cover - unexpected errors
2753
- exit_code = 1
2754
- logger.exception("content.regex_unexpected_error")
2755
- typer.echo(f"Error: {exc}", err=True)
2756
- finally:
2757
- finished_at = datetime.now(UTC)
2758
- server_label = server_key or (server.lower() if server else "internal")
2759
- _record_summary(
2760
- parent_ctx,
2761
- command="content.regex",
2762
- args=[page_id, f"pattern={pattern}"],
2763
- server=server_label,
2764
- exit_code=exit_code,
2765
- started_at=started_at,
2766
- finished_at=finished_at,
2767
- )
2768
- if exit_code != 0:
2769
- raise typer.Exit(code=exit_code) from None
2770
-
2771
-
2772
- @content_app.command("restrictions")
2773
- def content_restrictions(
2774
- ctx: typer.Context,
2775
- page_id: str = typer.Argument(..., help="Confluence page ID"),
2776
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2777
- json_output: bool = typer.Option(False, "--json", help="Emit JSON payload"),
2778
- ) -> None:
2779
- """Get all restrictions for content."""
2780
- parent_ctx = _parent_context(ctx)
2781
- started_at = datetime.now(UTC)
2782
- exit_code = 0
2783
- result_payload: dict[str, Any] = {}
2784
- server_key: str | None = None
2785
-
2786
- try:
2787
- settings = load_settings(strict=True)
2788
- server_key = _normalise_server(server, settings)
2789
- client = _build_http_client(settings, server_key)
2790
-
2791
- result = client.get_all_restrictions_for_content(page_id)
2792
- result_payload = {"page_id": page_id, "restrictions": result}
2793
-
2794
- if json_output or not sys.stdout.isatty():
2795
- _emit_json(result_payload)
2796
- else:
2797
- typer.echo(json.dumps(result_payload, indent=2, sort_keys=True))
2798
-
2799
- except (VDSClientError, typer.BadParameter) as exc:
2800
- exit_code = 1
2801
- logger.exception("content.restrictions_failed: %s", exc)
2802
- typer.echo(f"Error: {exc}", err=True)
2803
- except Exception as exc: # pragma: no cover - unexpected errors
2804
- exit_code = 1
2805
- logger.exception("content.restrictions_unexpected_error")
2806
- typer.echo(f"Error: {exc}", err=True)
2807
- finally:
2808
- finished_at = datetime.now(UTC)
2809
- server_label = server_key or (server.lower() if server else "internal")
2810
- _record_summary(
2811
- parent_ctx,
2812
- command="content.restrictions",
2813
- args=[page_id],
2814
- server=server_label,
2815
- exit_code=exit_code,
2816
- started_at=started_at,
2817
- finished_at=finished_at,
2818
- )
2819
- if exit_code != 0:
2820
- raise typer.Exit(code=exit_code) from None
2821
-
2822
-
2823
- @content_app.command("create-template")
2824
- def content_create_template(
2825
- ctx: typer.Context,
2826
- name: str = typer.Option(..., "--name", "-n", help="Template name"),
2827
- body_file: Path = typer.Option(
2828
- ..., "--body-file", exists=True, file_okay=True, dir_okay=False, help="Path to storage-format body"
2829
- ),
2830
- template_type: str = typer.Option("page", "--type", help="Template type (page or other supported types)"),
2831
- space_key: str | None = typer.Option(None, "--space", help="Limit template to space key"),
2832
- description: str | None = typer.Option(None, "--description", help="Template description"),
2833
- representation: str = typer.Option("storage", "--representation", help="Content representation"),
2834
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2835
- ) -> None:
2836
- """Create a new Confluence page template."""
2837
- parent_ctx = _parent_context(ctx)
2838
- _ensure_v1_api(parent_ctx, "content.create-template")
2839
- started_at = datetime.now(UTC)
2840
- try:
2841
- settings = load_settings(strict=True)
2842
- server_key = _normalise_server(server, settings)
2843
- client = ContentClient(_build_http_client(settings, server_key))
2844
- body = _read_text_file(body_file)
2845
- payload = client.create_template(
2846
- name=name,
2847
- body=body,
2848
- template_type=template_type,
2849
- space_key=space_key,
2850
- description=description,
2851
- representation=representation,
2852
- )
2853
- _emit_json(payload)
2854
- except Exception as exc:
2855
- logger.exception("content.create-template failed", extra={"name": name, "space": space_key})
2856
- typer.echo(f"Error: {exc}", err=True)
2857
- raise typer.Exit(code=1) from None
2858
- else:
2859
- finished_at = datetime.now(UTC)
2860
- args = [name, f"type={template_type}"]
2861
- if space_key:
2862
- args.append(f"space={space_key}")
2863
- _record_summary(
2864
- parent_ctx,
2865
- command="content.create-template",
2866
- args=args,
2867
- server=server_key,
2868
- exit_code=0,
2869
- started_at=started_at,
2870
- finished_at=finished_at,
2871
- )
2872
-
2873
-
2874
- @content_app.command("update-template")
2875
- def content_update_template(
2876
- ctx: typer.Context,
2877
- template_id: str = typer.Argument(..., help="Template identifier"),
2878
- name: str | None = typer.Option(None, "--name", help="Template name"),
2879
- body_file: Path | None = typer.Option(
2880
- None, "--body-file", exists=True, file_okay=True, dir_okay=False, help="Path to storage-format body"
2881
- ),
2882
- description: str | None = typer.Option(None, "--description", help="Template description"),
2883
- template_type: str | None = typer.Option(None, "--type", help="Template type"),
2884
- representation: str = typer.Option("storage", "--representation", help="Representation for --body-file"),
2885
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2886
- ) -> None:
2887
- """Update an existing Confluence page template."""
2888
- parent_ctx = _parent_context(ctx)
2889
- _ensure_v1_api(parent_ctx, "content.update-template")
2890
- if name is None and body_file is None and description is None and template_type is None:
2891
- raise typer.BadParameter("Provide at least one of --name, --body-file, --description, or --type")
2892
- body = _read_text_file(body_file) if body_file else None
2893
- started_at = datetime.now(UTC)
2894
- try:
2895
- settings = load_settings(strict=True)
2896
- server_key = _normalise_server(server, settings)
2897
- client = ContentClient(_build_http_client(settings, server_key))
2898
- payload = client.update_template(
2899
- template_id,
2900
- name=name,
2901
- body=body,
2902
- description=description,
2903
- representation=representation,
2904
- template_type=template_type,
2905
- )
2906
- _emit_json(payload)
2907
- except Exception as exc:
2908
- logger.exception("content.update-template failed", extra={"template_id": template_id})
2909
- typer.echo(f"Error: {exc}", err=True)
2910
- raise typer.Exit(code=1) from None
2911
- else:
2912
- finished_at = datetime.now(UTC)
2913
- args = [template_id]
2914
- if name:
2915
- args.append(f"name={name}")
2916
- _record_summary(
2917
- parent_ctx,
2918
- command="content.update-template",
2919
- args=args,
2920
- server=server_key,
2921
- exit_code=0,
2922
- started_at=started_at,
2923
- finished_at=finished_at,
2924
- )
2925
-
2926
-
2927
- @content_app.command("delete-template")
2928
- def content_delete_template(
2929
- ctx: typer.Context,
2930
- template_id: str = typer.Argument(..., help="Template identifier"),
2931
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2932
- ) -> None:
2933
- """Delete a Confluence page template."""
2934
- parent_ctx = _parent_context(ctx)
2935
- _ensure_v1_api(parent_ctx, "content.delete-template")
2936
- started_at = datetime.now(UTC)
2937
- try:
2938
- settings = load_settings(strict=True)
2939
- server_key = _normalise_server(server, settings)
2940
- client = ContentClient(_build_http_client(settings, server_key))
2941
- client.delete_template(template_id)
2942
- typer.echo(f"Deleted template {template_id}")
2943
- except Exception as exc:
2944
- logger.exception("content.delete-template failed", extra={"template_id": template_id})
2945
- typer.echo(f"Error: {exc}", err=True)
2946
- raise typer.Exit(code=1) from None
2947
- else:
2948
- finished_at = datetime.now(UTC)
2949
- _record_summary(
2950
- parent_ctx,
2951
- command="content.delete-template",
2952
- args=[template_id],
2953
- server=server_key,
2954
- exit_code=0,
2955
- started_at=started_at,
2956
- finished_at=finished_at,
2957
- )
2958
-
2959
-
2960
- # ---------------------------------------------------------------------------
2961
- # Diagnostics
2962
- # ---------------------------------------------------------------------------
2963
-
2964
-
2965
- @app.command("env")
2966
- def cmd_env(_ctx: typer.Context) -> None:
2967
- """Show Confluence connection environment variable status."""
2968
- settings = load_settings(strict=False)
2969
- typer.echo(
2970
- f"Default server: {settings.default_server}\n"
2971
- f"Internal URL: {settings.internal_url}\n"
2972
- f"External URL: {settings.external_url}\n"
2973
- f"Internal token set: {bool(settings.internal_token)}\n"
2974
- f"External token set: {bool(settings.external_token)}"
2975
- )
2976
-
2977
-
2978
- # ---------------------------------------------------------------------------
2979
- # Sync Commands (delegate to standalone scripts)
2980
- # ---------------------------------------------------------------------------
2981
-
2982
- sync_app = typer.Typer(help="Sync attachments from local files to Confluence")
2983
- app.add_typer(sync_app, name="sync")
2984
-
2985
-
2986
- @sync_app.command("pngs")
2987
- def cmd_sync_pngs(
2988
- _ctx: typer.Context,
2989
- page_id: str = typer.Argument(..., help="Confluence page ID"),
2990
- directory: Path = typer.Option(..., "--dir", "-d", help="Directory containing PNG files"),
2991
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
2992
- pattern: str | None = typer.Option(None, "--pattern", "-p", help="Filter PNG files by pattern"),
2993
- dry_run: bool = typer.Option(False, "--dry-run", help="Show what would be done without making changes"),
2994
- comment: str | None = typer.Option(None, "--comment", "-c", help="Comment for attachment updates"),
2995
- yes: bool = typer.Option(False, "--yes", "-y", help="Auto-confirm without prompting"),
2996
- ) -> None:
2997
- """Sync local PNG files with Confluence page attachments."""
2998
- import subprocess
2999
- import sys
3000
-
3001
- # Project root for confluence_orchestrator (where sync scripts live)
3002
- script_path = Path(__file__).resolve().parents[2] / "sync_png_attachments.py"
3003
- if not script_path.exists():
3004
- typer.echo(f"Error: Sync script not found: {script_path}", err=True)
3005
- raise typer.Exit(code=1) from None
3006
-
3007
- cmd = [
3008
- sys.executable,
3009
- str(script_path),
3010
- "sync",
3011
- page_id,
3012
- "--dir",
3013
- str(directory),
3014
- ]
3015
- if server:
3016
- cmd.extend(["--server", server])
3017
- if pattern:
3018
- cmd.extend(["--pattern", pattern])
3019
- if dry_run:
3020
- cmd.append("--dry-run")
3021
- if comment:
3022
- cmd.extend(["--comment", comment])
3023
- if yes:
3024
- cmd.append("--yes")
3025
-
3026
- result = subprocess.run(cmd, check=False)
3027
- raise typer.Exit(code=result.returncode) from None
3028
-
3029
-
3030
- @sync_app.command("pdfs")
3031
- def cmd_sync_pdfs(
3032
- _ctx: typer.Context,
3033
- page_id: str = typer.Argument(..., help="Confluence page ID"),
3034
- directory: Path = typer.Option(..., "--dir", "-d", help="Directory containing PDF files"),
3035
- server: str | None = typer.Option(None, "--server", "-s", help="internal|external"),
3036
- pattern: str | None = typer.Option(None, "--pattern", "-p", help="Filter PDF files by pattern"),
3037
- dry_run: bool = typer.Option(False, "--dry-run", help="Show what would be done without making changes"),
3038
- comment: str | None = typer.Option(None, "--comment", "-c", help="Comment for attachment updates"),
3039
- yes: bool = typer.Option(False, "--yes", "-y", help="Auto-confirm without prompting"),
3040
- ) -> None:
3041
- """Sync local PDF files with Confluence page attachments.
3042
-
3043
- This command delegates to the standalone sync_pdfs_to_confluence.py script.
3044
- For markdown-to-PDF sync, use the PDF orchestrator: vds-cli pdf -- md2pdf
3045
- """
3046
- import subprocess
3047
- import sys
3048
-
3049
- # Look for script in confluence_orchestrator/ directory (standard location)
3050
- script_path = Path(__file__).resolve().parents[2] / "sync_pdfs_to_confluence.py"
3051
-
3052
- if not script_path.exists():
3053
- typer.echo(
3054
- f"Error: Sync script not found: {script_path}\n"
3055
- "Note: Ensure sync_pdfs_to_confluence.py exists in confluence_orchestrator/ directory.",
3056
- err=True,
3057
- )
3058
- raise typer.Exit(code=1) from None
3059
-
3060
- cmd = [
3061
- sys.executable,
3062
- str(script_path),
3063
- "sync",
3064
- page_id,
3065
- "--dir",
3066
- str(directory),
3067
- ]
3068
- if server:
3069
- cmd.extend(["--server", server])
3070
- if pattern:
3071
- cmd.extend(["--pattern", pattern])
3072
- if dry_run:
3073
- cmd.append("--dry-run")
3074
- if comment:
3075
- cmd.extend(["--comment", comment])
3076
- if yes:
3077
- cmd.append("--yes")
3078
-
3079
- result = subprocess.run(cmd, check=False)
3080
- raise typer.Exit(code=result.returncode) from None
3081
-
3082
-
3083
- # ---------------------------------------------------------------------------
3084
- # content copy-tree
3085
- # ---------------------------------------------------------------------------
3086
-
3087
-
3088
- @content_app.command("copy-tree")
3089
- def content_copy_tree(
3090
- ctx: typer.Context,
3091
- source_page_id: str = typer.Argument(..., help="Source root page ID"),
3092
- target_page_id: str = typer.Option(..., "--target-page-id", help="Target root page ID"),
3093
- source_server: str = typer.Option(
3094
- "external", "--source-server", help="Source Confluence server (internal|external)"
3095
- ),
3096
- target_server: str = typer.Option(
3097
- "internal", "--target-server", help="Target Confluence server (internal|external)"
3098
- ),
3099
- source_space: str | None = typer.Option(
3100
- None, "--source-space", help="Source space key (auto-detected from source page if omitted)"
3101
- ),
3102
- target_space: str = typer.Option(..., "--target-space", help="Target space key"),
3103
- skip_attachments: bool = typer.Option(False, "--skip-attachments", help="Skip attachment copy"),
3104
- skip_labels: bool = typer.Option(False, "--skip-labels", help="Skip label copy"),
3105
- skip_link_remap: bool = typer.Option(False, "--skip-link-remap", help="Skip link remapping"),
3106
- max_depth: int | None = typer.Option(None, "--max-depth", help="Max BFS depth (0=root only; max: 100)"),
3107
- dry_run: bool = typer.Option(False, "--dry-run", help="Report what would be copied without writing"),
3108
- ) -> None:
3109
- """Copy a Confluence page tree from one space/server to another."""
3110
- parent_ctx = _parent_context(ctx)
3111
- if max_depth is not None and max_depth > 100:
3112
- raise typer.BadParameter("--max-depth cannot exceed 100 (NFR-05)")
3113
- started_at = datetime.now(UTC)
3114
- source_server_key: str = ""
3115
- try:
3116
- settings = load_settings(strict=True)
3117
- source_server_key = _normalise_server(source_server, settings)
3118
- target_server_key = _normalise_server(target_server, settings)
3119
- source_client = ContentClient(_build_http_client(settings, source_server_key))
3120
- target_client = ContentClient(_build_http_client(settings, target_server_key))
3121
- if source_space:
3122
- resolved_source_space = source_space
3123
- else:
3124
- src_page = source_client.get_page(source_page_id, expand=["space"])
3125
- space_info = src_page.get("space")
3126
- if not isinstance(space_info, dict) or not space_info.get("key"):
3127
- raise VDSClientError(
3128
- f"Cannot determine source space key from page {source_page_id}. Pass --source-space explicitly.",
3129
- context={"source_page_id": source_page_id},
3130
- )
3131
- resolved_source_space = str(space_info["key"])
3132
- options = CopyOptions(
3133
- skip_attachments=skip_attachments,
3134
- skip_labels=skip_labels,
3135
- skip_link_remap=skip_link_remap,
3136
- dry_run=dry_run,
3137
- max_depth=max_depth,
3138
- )
3139
- copier = TreeCopier(source_client, target_client, target_space, resolved_source_space, options)
3140
- result = copier.copy_tree(source_page_id, target_page_id)
3141
- _emit_json(asdict(result))
3142
- except Exception as exc:
3143
- logger.exception("content.copy-tree failed", extra={"source_page_id": source_page_id})
3144
- typer.echo(f"Error: {exc}", err=True)
3145
- raise typer.Exit(code=1) from None
3146
- else:
3147
- finished_at = datetime.now(UTC)
3148
- _record_summary(
3149
- parent_ctx,
3150
- command="content.copy-tree",
3151
- args=[source_page_id, f"target={target_page_id}", f"target_space={target_space}"],
3152
- server=source_server_key,
3153
- exit_code=0,
3154
- started_at=started_at,
3155
- finished_at=finished_at,
3156
- )
3157
-
3158
-
3159
- if __name__ == "__main__":
3160
- app()