bc-cli 0.3.0__tar.gz → 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (326) hide show
  1. {bc_cli-0.3.0 → bc_cli-0.5.0}/.gitignore +8 -0
  2. bc_cli-0.5.0/CHANGELOG.md +548 -0
  3. {bc_cli-0.3.0 → bc_cli-0.5.0}/PKG-INFO +8 -1
  4. bc_cli-0.5.0/bcli-site/README.md +46 -0
  5. bc_cli-0.5.0/bcli-site/src/components/CodeBlock.astro +14 -0
  6. bc_cli-0.5.0/bcli-site/src/components/Hero.astro +32 -0
  7. bc_cli-0.5.0/bcli-site/src/pages/index.astro +118 -0
  8. bc_cli-0.5.0/bcli-site/src/styles/global.css +27 -0
  9. {bc_cli-0.3.0 → bc_cli-0.5.0}/docs/mcp-server.md +54 -31
  10. {bc_cli-0.3.0 → bc_cli-0.5.0}/docs/saved-queries.md +74 -1
  11. bc_cli-0.5.0/packs/cronus-demo/batches/month-end-cronus.yaml +64 -0
  12. bc_cli-0.5.0/packs/cronus-demo/fragments/cronus-orientation.md +30 -0
  13. bc_cli-0.5.0/packs/cronus-demo/fragments/month-end-walkthrough.md +45 -0
  14. bc_cli-0.5.0/packs/cronus-demo/pack.yaml +23 -0
  15. bc_cli-0.5.0/packs/cronus-demo/queries/cronus-sample.yaml +53 -0
  16. bc_cli-0.5.0/packs/starter-generic/batches/month-end-readonly-audit.yaml +39 -0
  17. bc_cli-0.5.0/packs/starter-generic/batches/weekly-ar-snapshot.yaml +35 -0
  18. bc_cli-0.5.0/packs/starter-generic/fragments/common-errors.md +50 -0
  19. bc_cli-0.5.0/packs/starter-generic/fragments/endpoint-discovery.md +39 -0
  20. bc_cli-0.5.0/packs/starter-generic/fragments/filter-syntax-cheatsheet.md +51 -0
  21. bc_cli-0.5.0/packs/starter-generic/pack.yaml +31 -0
  22. bc_cli-0.5.0/packs/starter-generic/queries/ar-aging-buckets.yaml +17 -0
  23. bc_cli-0.5.0/packs/starter-generic/queries/customer-by-no.yaml +11 -0
  24. bc_cli-0.5.0/packs/starter-generic/queries/inventory-on-hand.yaml +14 -0
  25. bc_cli-0.5.0/packs/starter-generic/queries/open-pos.yaml +14 -0
  26. bc_cli-0.5.0/packs/starter-generic/queries/recent-posted-invoices.yaml +18 -0
  27. bc_cli-0.5.0/packs/starter-generic/queries/vendor-by-no.yaml +11 -0
  28. {bc_cli-0.3.0 → bc_cli-0.5.0}/pyproject.toml +29 -1
  29. bc_cli-0.5.0/src/bcli/ask/__init__.py +32 -0
  30. bc_cli-0.5.0/src/bcli/ask/_claude.py +160 -0
  31. bc_cli-0.5.0/src/bcli/ask/_factory.py +98 -0
  32. bc_cli-0.5.0/src/bcli/ask/_openai.py +165 -0
  33. bc_cli-0.5.0/src/bcli/ask/_protocol.py +72 -0
  34. bc_cli-0.5.0/src/bcli/ask/_providers.py +106 -0
  35. bc_cli-0.5.0/src/bcli/batch/__init__.py +9 -0
  36. bc_cli-0.5.0/src/bcli/batch/ledger.py +563 -0
  37. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/client/_async.py +148 -4
  38. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/client/_transport.py +40 -6
  39. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/config/_model.py +64 -0
  40. bc_cli-0.5.0/src/bcli/context/__init__.py +82 -0
  41. bc_cli-0.5.0/src/bcli/context/_bundle.py +318 -0
  42. bc_cli-0.5.0/src/bcli/context/_http_tail.py +173 -0
  43. bc_cli-0.5.0/src/bcli/context/_last_error.py +286 -0
  44. bc_cli-0.5.0/src/bcli/context/_protocol.py +414 -0
  45. bc_cli-0.5.0/src/bcli/context/_redact.py +411 -0
  46. bc_cli-0.5.0/src/bcli/exit_codes.py +69 -0
  47. bc_cli-0.5.0/src/bcli/packs/__init__.py +81 -0
  48. bc_cli-0.5.0/src/bcli/packs/_installer.py +710 -0
  49. bc_cli-0.5.0/src/bcli/packs/_ledger.py +294 -0
  50. bc_cli-0.5.0/src/bcli/packs/_loader.py +282 -0
  51. bc_cli-0.5.0/src/bcli/packs/_protocol.py +171 -0
  52. bc_cli-0.5.0/src/bcli/packs/_registry.py +148 -0
  53. bc_cli-0.5.0/src/bcli/result_envelope.py +140 -0
  54. bc_cli-0.5.0/src/bcli/workflow/_models.py +114 -0
  55. bc_cli-0.5.0/src/bcli_cli/_envelope_wrap.py +344 -0
  56. bc_cli-0.5.0/src/bcli_cli/_error_handler.py +140 -0
  57. bc_cli-0.5.0/src/bcli_cli/_progress.py +92 -0
  58. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/_safety.py +6 -5
  59. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/app.py +105 -4
  60. bc_cli-0.5.0/src/bcli_cli/commands/action_cmd.py +215 -0
  61. bc_cli-0.5.0/src/bcli_cli/commands/ask_cmd.py +234 -0
  62. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/commands/attach_cmd.py +81 -45
  63. bc_cli-0.5.0/src/bcli_cli/commands/batch_cmd.py +1123 -0
  64. bc_cli-0.5.0/src/bcli_cli/commands/delete_cmd.py +119 -0
  65. bc_cli-0.5.0/src/bcli_cli/commands/describe_cmd.py +562 -0
  66. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/commands/extract_cmd.py +47 -0
  67. bc_cli-0.5.0/src/bcli_cli/commands/pack_cmd.py +339 -0
  68. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/commands/patch_cmd.py +61 -19
  69. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/commands/post_cmd.py +63 -16
  70. bc_cli-0.5.0/src/bcli_cli/commands/skill_cmd.py +599 -0
  71. bc_cli-0.5.0/src/bcli_cli/commands/skill_init_cmd.py +755 -0
  72. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/output/_formatters.py +19 -10
  73. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_mcp/__main__.py +2 -2
  74. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_mcp/_runner.py +38 -32
  75. bc_cli-0.5.0/src/bcli_mcp/_server.py +243 -0
  76. bc_cli-0.5.0/src/bcli_mcp/_tool_generator.py +195 -0
  77. bc_cli-0.5.0/tests/test_ask/test_cli_dry_run.py +158 -0
  78. bc_cli-0.5.0/tests/test_ask/test_factory.py +138 -0
  79. bc_cli-0.5.0/tests/test_ask/test_providers.py +153 -0
  80. bc_cli-0.5.0/tests/test_batch_ledger/test_batch_cmd_ledger.py +265 -0
  81. bc_cli-0.5.0/tests/test_batch_ledger/test_idempotency_replay.py +225 -0
  82. bc_cli-0.5.0/tests/test_batch_ledger/test_ledger_idempotency.py +214 -0
  83. bc_cli-0.5.0/tests/test_batch_ledger/test_ledger_schema.py +340 -0
  84. bc_cli-0.5.0/tests/test_batch_ledger/test_rollback_cmd.py +299 -0
  85. bc_cli-0.5.0/tests/test_batch_ledger/test_state_list_cmds.py +124 -0
  86. bc_cli-0.5.0/tests/test_cli/test_action_cmd.py +188 -0
  87. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_cli/test_batch_safety.py +13 -1
  88. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_cli/test_output_format.py +9 -2
  89. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_cli/test_safety.py +2 -2
  90. bc_cli-0.5.0/tests/test_context/test_bundle.py +167 -0
  91. bc_cli-0.5.0/tests/test_context/test_http_tail.py +134 -0
  92. bc_cli-0.5.0/tests/test_context/test_last_error.py +135 -0
  93. bc_cli-0.5.0/tests/test_context/test_protocol.py +180 -0
  94. bc_cli-0.5.0/tests/test_context/test_redact.py +191 -0
  95. bc_cli-0.5.0/tests/test_describe/__init__.py +1 -0
  96. bc_cli-0.5.0/tests/test_describe/test_describe_cmd.py +493 -0
  97. bc_cli-0.5.0/tests/test_describe/test_describe_positionals_limits.py +119 -0
  98. bc_cli-0.5.0/tests/test_envelope/conftest.py +143 -0
  99. bc_cli-0.5.0/tests/test_envelope/test_batch_envelope_with_ledger.py +286 -0
  100. bc_cli-0.5.0/tests/test_envelope/test_envelope_other_verbs.py +245 -0
  101. bc_cli-0.5.0/tests/test_envelope/test_envelope_policy_violation.py +163 -0
  102. bc_cli-0.5.0/tests/test_envelope/test_envelope_post.py +289 -0
  103. bc_cli-0.5.0/tests/test_envelope/test_result_envelope.py +165 -0
  104. bc_cli-0.5.0/tests/test_errors/__init__.py +1 -0
  105. bc_cli-0.5.0/tests/test_errors/test_did_you_mean.py +116 -0
  106. bc_cli-0.5.0/tests/test_exit_codes/__init__.py +1 -0
  107. bc_cli-0.5.0/tests/test_exit_codes/test_taxonomy.py +57 -0
  108. bc_cli-0.5.0/tests/test_idempotency/__init__.py +1 -0
  109. bc_cli-0.5.0/tests/test_idempotency/conftest.py +64 -0
  110. bc_cli-0.5.0/tests/test_idempotency/test_cli_flags.py +135 -0
  111. bc_cli-0.5.0/tests/test_idempotency/test_idempotency_key.py +117 -0
  112. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_mcp/test_runner.py +66 -33
  113. bc_cli-0.5.0/tests/test_mcp/test_server_tools.py +328 -0
  114. bc_cli-0.5.0/tests/test_mcp/test_tool_generator.py +395 -0
  115. bc_cli-0.5.0/tests/test_output/__init__.py +1 -0
  116. bc_cli-0.5.0/tests/test_output/test_json_on_pipe.py +85 -0
  117. bc_cli-0.5.0/tests/test_packs/__init__.py +0 -0
  118. bc_cli-0.5.0/tests/test_packs/conftest.py +106 -0
  119. bc_cli-0.5.0/tests/test_packs/test_builtins.py +106 -0
  120. bc_cli-0.5.0/tests/test_packs/test_installer.py +219 -0
  121. bc_cli-0.5.0/tests/test_packs/test_loader.py +93 -0
  122. bc_cli-0.5.0/tests/test_packs/test_registry.py +46 -0
  123. bc_cli-0.5.0/tests/test_progress/__init__.py +1 -0
  124. bc_cli-0.5.0/tests/test_progress/test_progress_events.py +157 -0
  125. bc_cli-0.5.0/tests/test_registry/__init__.py +0 -0
  126. bc_cli-0.5.0/tests/test_skill_init/__init__.py +0 -0
  127. bc_cli-0.5.0/tests/test_skill_init/conftest.py +147 -0
  128. bc_cli-0.5.0/tests/test_skill_init/test_skill_init_wizard.py +555 -0
  129. bc_cli-0.5.0/tests/test_skill_install/__init__.py +1 -0
  130. bc_cli-0.5.0/tests/test_skill_install/test_skill_install.py +484 -0
  131. bc_cli-0.5.0/tests/test_telemetry/__init__.py +0 -0
  132. bc_cli-0.5.0/tests/test_url/__init__.py +0 -0
  133. bc_cli-0.5.0/tests/test_url/test_bound_action_resolve.py +204 -0
  134. bc_cli-0.5.0/tests/test_workflow/__init__.py +0 -0
  135. bc_cli-0.5.0/tests/test_workflow/test_method_alias.py +153 -0
  136. bc_cli-0.5.0/tests/test_workflow/test_rollback_url_bound_action.py +61 -0
  137. bc_cli-0.3.0/.env.example +0 -5
  138. bc_cli-0.3.0/.github/ISSUE_TEMPLATE/bug_report.md +0 -39
  139. bc_cli-0.3.0/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  140. bc_cli-0.3.0/.github/PULL_REQUEST_TEMPLATE.md +0 -23
  141. bc_cli-0.3.0/.github/workflows/publish.yml +0 -90
  142. bc_cli-0.3.0/.github/workflows/tests.yml +0 -50
  143. bc_cli-0.3.0/AGENTS.md +0 -258
  144. bc_cli-0.3.0/CHANGELOG.md +0 -254
  145. bc_cli-0.3.0/CODE_OF_CONDUCT.md +0 -76
  146. bc_cli-0.3.0/CONTRIBUTING.md +0 -87
  147. bc_cli-0.3.0/SECURITY.md +0 -32
  148. bc_cli-0.3.0/src/bcli/workflow/_models.py +0 -68
  149. bc_cli-0.3.0/src/bcli_cli/commands/batch_cmd.py +0 -416
  150. bc_cli-0.3.0/src/bcli_cli/commands/delete_cmd.py +0 -76
  151. bc_cli-0.3.0/src/bcli_mcp/_server.py +0 -162
  152. bc_cli-0.3.0/tests/test_mcp/test_server_tools.py +0 -215
  153. bc_cli-0.3.0/uv.lock +0 -3330
  154. {bc_cli-0.3.0 → bc_cli-0.5.0}/LICENSE +0 -0
  155. {bc_cli-0.3.0 → bc_cli-0.5.0}/NOTICE +0 -0
  156. {bc_cli-0.3.0 → bc_cli-0.5.0}/README.md +0 -0
  157. {bc_cli-0.3.0 → bc_cli-0.5.0}/docs/authentication.md +0 -0
  158. {bc_cli-0.3.0 → bc_cli-0.5.0}/docs/batch-operations.md +0 -0
  159. {bc_cli-0.3.0 → bc_cli-0.5.0}/docs/business-central-admin-setup.md +0 -0
  160. {bc_cli-0.3.0 → bc_cli-0.5.0}/docs/command-reference.md +0 -0
  161. {bc_cli-0.3.0 → bc_cli-0.5.0}/docs/configuration.md +0 -0
  162. {bc_cli-0.3.0 → bc_cli-0.5.0}/docs/contributing.md +0 -0
  163. {bc_cli-0.3.0 → bc_cli-0.5.0}/docs/custom-apis.md +0 -0
  164. {bc_cli-0.3.0 → bc_cli-0.5.0}/docs/demo-setup.md +0 -0
  165. {bc_cli-0.3.0 → bc_cli-0.5.0}/docs/extraction.md +0 -0
  166. {bc_cli-0.3.0 → bc_cli-0.5.0}/docs/getting-started.md +0 -0
  167. {bc_cli-0.3.0 → bc_cli-0.5.0}/docs/multi-company.md +0 -0
  168. {bc_cli-0.3.0 → bc_cli-0.5.0}/docs/plans/team-deployment.md +0 -0
  169. {bc_cli-0.3.0 → bc_cli-0.5.0}/docs/querying.md +0 -0
  170. {bc_cli-0.3.0 → bc_cli-0.5.0}/docs/sdk-usage.md +0 -0
  171. {bc_cli-0.3.0 → bc_cli-0.5.0}/docs/write-operations.md +0 -0
  172. {bc_cli-0.3.0 → bc_cli-0.5.0}/examples/ap-monthly-review.yaml +0 -0
  173. {bc_cli-0.3.0 → bc_cli-0.5.0}/examples/attach-purchase-invoice-pdf.yaml +0 -0
  174. {bc_cli-0.3.0 → bc_cli-0.5.0}/examples/create-purchase-invoice.yaml +0 -0
  175. {bc_cli-0.3.0 → bc_cli-0.5.0}/examples/extract/purchase_invoice_lines.yaml +0 -0
  176. {bc_cli-0.3.0 → bc_cli-0.5.0}/examples/month-end-cronus.yaml +0 -0
  177. {bc_cli-0.3.0 → bc_cli-0.5.0}/examples/queries/sample.yaml +0 -0
  178. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/__init__.py +0 -0
  179. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/_url.py +0 -0
  180. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/_version.py +0 -0
  181. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/audit/__init__.py +0 -0
  182. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/audit/_factory.py +0 -0
  183. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/audit/_protocol.py +0 -0
  184. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/audit/_redact.py +0 -0
  185. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/auth/__init__.py +0 -0
  186. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/auth/_base.py +0 -0
  187. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/auth/_browser.py +0 -0
  188. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/auth/_credentials.py +0 -0
  189. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/auth/_device_code.py +0 -0
  190. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/auth/_secure_io.py +0 -0
  191. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/auth/_token_cache.py +0 -0
  192. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/bundle/__init__.py +0 -0
  193. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/bundle/_apply.py +0 -0
  194. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/bundle/_fetch.py +0 -0
  195. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/bundle/_manifest.py +0 -0
  196. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/bundle/_publish.py +0 -0
  197. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/bundle/_verify.py +0 -0
  198. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/client/__init__.py +0 -0
  199. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/client/_safety.py +0 -0
  200. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/client/_sync.py +0 -0
  201. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/config/__init__.py +0 -0
  202. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/config/_defaults.py +0 -0
  203. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/config/_loader.py +0 -0
  204. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/diagnostics/__init__.py +0 -0
  205. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/diagnostics/_checks.py +0 -0
  206. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/errors.py +0 -0
  207. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/etl/__init__.py +0 -0
  208. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/etl/_auth.py +0 -0
  209. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/etl/_bridge.py +0 -0
  210. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/etl/_client.py +0 -0
  211. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/etl/_generic.py +0 -0
  212. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/etl/_polaris.py +0 -0
  213. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/etl/_stampers.py +0 -0
  214. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/extract/__init__.py +0 -0
  215. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/extract/_claude.py +0 -0
  216. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/extract/_factory.py +0 -0
  217. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/extract/_openai.py +0 -0
  218. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/extract/_pdf.py +0 -0
  219. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/extract/_protocol.py +0 -0
  220. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/extract/_schema.py +0 -0
  221. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/extract/_yaml_writer.py +0 -0
  222. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/odata/__init__.py +0 -0
  223. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/odata/_escape.py +0 -0
  224. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/odata/_filter_fields.py +0 -0
  225. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/odata/_pagination.py +0 -0
  226. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/odata/_query.py +0 -0
  227. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/odata/_response.py +0 -0
  228. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/py.typed +0 -0
  229. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/registry/__init__.py +0 -0
  230. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/registry/_importers.py +0 -0
  231. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/registry/_registry.py +0 -0
  232. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/registry/_schema.py +0 -0
  233. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/registry/standard_v2.json +0 -0
  234. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/telemetry/__init__.py +0 -0
  235. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/telemetry/_azure_monitor.py +0 -0
  236. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/telemetry/_factory.py +0 -0
  237. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/telemetry/_protocol.py +0 -0
  238. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/telemetry/events.py +0 -0
  239. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/workflow/__init__.py +0 -0
  240. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/workflow/_loader.py +0 -0
  241. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/workflow/_query_search.py +0 -0
  242. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli/workflow/_resolver.py +0 -0
  243. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/__init__.py +0 -0
  244. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/_audit_wrap.py +0 -0
  245. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/_dry_run.py +0 -0
  246. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/_state.py +0 -0
  247. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/_url_resolve.py +0 -0
  248. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/commands/__init__.py +0 -0
  249. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/commands/auth_cmd.py +0 -0
  250. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/commands/company_cmd.py +0 -0
  251. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/commands/config_cmd.py +0 -0
  252. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/commands/context_cmd.py +0 -0
  253. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/commands/doctor_cmd.py +0 -0
  254. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/commands/endpoint_cmd.py +0 -0
  255. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/commands/env_cmd.py +0 -0
  256. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/commands/etl_cmd.py +0 -0
  257. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/commands/get_cmd.py +0 -0
  258. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/commands/query_cmd.py +0 -0
  259. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/commands/refresh_cmd.py +0 -0
  260. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/commands/registry_cmd.py +0 -0
  261. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/commands/test_cmd.py +0 -0
  262. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/output/__init__.py +0 -0
  263. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_cli/output/_display.py +0 -0
  264. {bc_cli-0.3.0 → bc_cli-0.5.0}/src/bcli_mcp/__init__.py +0 -0
  265. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/conftest.py +0 -0
  266. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/fixtures/sample_postman_collection.json +0 -0
  267. {bc_cli-0.3.0/tests/test_audit → bc_cli-0.5.0/tests/test_ask}/__init__.py +0 -0
  268. {bc_cli-0.3.0/tests/test_auth → bc_cli-0.5.0/tests/test_audit}/__init__.py +0 -0
  269. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_audit/test_factory.py +0 -0
  270. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_audit/test_redact.py +0 -0
  271. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_audit/test_sink.py +0 -0
  272. {bc_cli-0.3.0/tests/test_bundle → bc_cli-0.5.0/tests/test_auth}/__init__.py +0 -0
  273. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_auth/test_browser_auth.py +0 -0
  274. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_auth/test_secure_io.py +0 -0
  275. {bc_cli-0.3.0/tests/test_cli → bc_cli-0.5.0/tests/test_batch_ledger}/__init__.py +0 -0
  276. {bc_cli-0.3.0/tests/test_client → bc_cli-0.5.0/tests/test_bundle}/__init__.py +0 -0
  277. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_bundle/test_bundle_roundtrip.py +0 -0
  278. {bc_cli-0.3.0/tests/test_config → bc_cli-0.5.0/tests/test_cli}/__init__.py +0 -0
  279. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_cli/test_audit_wrap.py +0 -0
  280. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_cli/test_company_cmd.py +0 -0
  281. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_cli/test_config_cmd.py +0 -0
  282. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_cli/test_dry_run.py +0 -0
  283. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_cli/test_pipe_handling.py +0 -0
  284. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_cli/test_query_cmd.py +0 -0
  285. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_cli/test_records_format.py +0 -0
  286. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_cli/test_state.py +0 -0
  287. {bc_cli-0.3.0/tests/test_diagnostics → bc_cli-0.5.0/tests/test_client}/__init__.py +0 -0
  288. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_client/test_resolve_url.py +0 -0
  289. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_client/test_safety.py +0 -0
  290. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_client/test_transport.py +0 -0
  291. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_client/test_upload_attachment.py +0 -0
  292. {bc_cli-0.3.0/tests/test_etl → bc_cli-0.5.0/tests/test_config}/__init__.py +0 -0
  293. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_config/test_config.py +0 -0
  294. {bc_cli-0.3.0/tests/test_extract → bc_cli-0.5.0/tests/test_context}/__init__.py +0 -0
  295. {bc_cli-0.3.0/tests/test_mcp → bc_cli-0.5.0/tests/test_diagnostics}/__init__.py +0 -0
  296. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_diagnostics/test_checks.py +0 -0
  297. {bc_cli-0.3.0/tests/test_odata → bc_cli-0.5.0/tests/test_envelope}/__init__.py +0 -0
  298. {bc_cli-0.3.0/tests/test_registry → bc_cli-0.5.0/tests/test_etl}/__init__.py +0 -0
  299. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_etl/test_bridge.py +0 -0
  300. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_etl/test_generic.py +0 -0
  301. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_etl/test_stampers.py +0 -0
  302. {bc_cli-0.3.0/tests/test_telemetry → bc_cli-0.5.0/tests/test_extract}/__init__.py +0 -0
  303. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_extract/test_claude.py +0 -0
  304. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_extract/test_factory.py +0 -0
  305. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_extract/test_openai.py +0 -0
  306. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_extract/test_pdf.py +0 -0
  307. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_extract/test_schema.py +0 -0
  308. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_extract/test_yaml_writer.py +0 -0
  309. {bc_cli-0.3.0/tests/test_url → bc_cli-0.5.0/tests/test_mcp}/__init__.py +0 -0
  310. {bc_cli-0.3.0/tests/test_workflow → bc_cli-0.5.0/tests/test_odata}/__init__.py +0 -0
  311. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_odata/test_escape.py +0 -0
  312. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_odata/test_filter_fields.py +0 -0
  313. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_odata/test_query.py +0 -0
  314. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_registry/test_caution.py +0 -0
  315. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_registry/test_importers.py +0 -0
  316. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_registry/test_metadata_fields.py +0 -0
  317. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_registry/test_registry.py +0 -0
  318. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_telemetry/test_events.py +0 -0
  319. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_telemetry/test_sink.py +0 -0
  320. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_url/test_origin_allowlist.py +0 -0
  321. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_url/test_url_builder.py +0 -0
  322. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_workflow/test_batch_integration.py +0 -0
  323. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_workflow/test_loader.py +0 -0
  324. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_workflow/test_models.py +0 -0
  325. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_workflow/test_query_search.py +0 -0
  326. {bc_cli-0.3.0 → bc_cli-0.5.0}/tests/test_workflow/test_resolver.py +0 -0
@@ -36,3 +36,11 @@ bcapi_cli_prd.md
36
36
 
37
37
  # Codex CLI session metadata — local-only, not part of the repo
38
38
  .context/
39
+
40
+ # bcli-site (Astro) — generated files
41
+ bcli-site/node_modules/
42
+ bcli-site/dist/
43
+ bcli-site/.astro/
44
+ bcli-site/pnpm-lock.yaml
45
+ bcli-site/package-lock.json
46
+ bcli-site/yarn.lock
@@ -0,0 +1,548 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.5.0] - 2026-05-25
11
+
12
+ ### Added — Part 3 (`bcli-site/` landing page v0)
13
+
14
+ - **`bcli-site/`** — Astro + Tailwind landing page scaffold for
15
+ bcli.sh. Single page (v0): hero, install instructions, three
16
+ example commands, features grid, GitHub link.
17
+ - Stack: Astro 4 + Tailwind 3 + TypeScript 5 (`extends:
18
+ astro/tsconfigs/strict`).
19
+ - Copy reflects what's actually shipped: packs, ask, MCP server,
20
+ describe. Does NOT oversell the deferred `bcli agent` mode (R9).
21
+ - `.github/workflows/site.yml` builds the site on changes under
22
+ `bcli-site/**`; Vercel deploy stub is wired but commented out
23
+ until `VERCEL_TOKEN` etc. are added to repo secrets.
24
+ - `bcli-site/node_modules`, `dist`, `.astro`, and lockfiles are
25
+ gitignored.
26
+
27
+ ### Added — Part 2 (`bcli ask`)
28
+
29
+ - **`bcli ask "<question>"`** — second-opinion oracle. Bundles the
30
+ operator's recent failing context (last-error, http-tail,
31
+ profile, describe excerpt) via :mod:`bcli.context`, ships it to
32
+ a configured LLM backend, and prints the answer. Opt-in: NullAsker
33
+ is the default; set `[ask] backend = "claude"` (or `"openai"`) to
34
+ activate.
35
+ - Built-in backends: `null` (default), `claude` (Anthropic — extras
36
+ `[ask-claude]`), `openai` (extras `[ask-openai]`). Third-party
37
+ backends register by import path `module.path:ClassName`. Mirror
38
+ of the `extract` factory shape exactly.
39
+ - **`--dry-run`** prints the exact redacted bundle that would be
40
+ sent before any network call. **`--no-context`** suppresses the
41
+ auto-bundle. **`--attach PATH`** pins a file with redaction +
42
+ truncation. **`--backend NAME`** is a one-shot override.
43
+ - **`bcli.ask.context_providers` entry-point group (R8)** —
44
+ downstream packages add domain-specific context (glossaries,
45
+ schema hints) via a registered callable. Strictly opt-in: a pack
46
+ may recommend a provider but never auto-enables it; user config
47
+ in `[ask] context_providers = [...]` is the binding decision.
48
+ - New `AskConfig` section in `bcli.config._model` exposing
49
+ `backend`, `model`, `api_key_env`, `max_tokens`,
50
+ `include_describe`, `include_http_tail`, `context_providers`.
51
+
52
+ ### Added — Part 1 (`bcli pack`)
53
+
54
+ - **`bcli pack`** command group: `list`, `info`, `install`,
55
+ `uninstall`. Discovers packs from three sources: built-in
56
+ (``packs/`` in the repo), entry-point group ``bcli.packs``, and
57
+ ``--path <dir>`` for local development.
58
+ - **Pack manifest format** (``pack.yaml``) with `agent_fragments`,
59
+ `queries`, `batches`, `registry_presets`, and
60
+ `recommended_context_providers`. Each fragment declares
61
+ `targets:` (`agents` and/or `claude`); default `[agents]` (R3).
62
+ - **Install ledger** at
63
+ ``~/.config/bcli/packs/<profile>/<pack>.json`` recording every
64
+ artefact written, with per-entry `rendered_hash` and `owner` so
65
+ uninstall is provenance-driven (R2).
66
+ - **Conflict detection** on registry presets (R7): a second pack
67
+ cannot silently overwrite an endpoint owned by another pack —
68
+ ``--replace-owned --accept-conflicts`` is the two-flag escape
69
+ hatch.
70
+ - **Idempotent re-install**: marker blocks in AGENTS.md / CLAUDE.md
71
+ are replaced in place via ID + content_hash, never duplicated.
72
+ - **Two built-in packs**: `starter-generic` (6 queries, 2 batches,
73
+ 3 fragments — uses only standard v2.0 endpoints) and
74
+ `cronus-demo` (Microsoft CRONUS demo workflow).
75
+
76
+ ### Added — Part 0 (context infrastructure for LLM features)
77
+
78
+ - **`bcli.context` package** — shared, model-bound context layer that
79
+ future LLM-driven features consume (`bcli ask`, future `bcli agent`).
80
+ Standalone in this release; no CLI consumers yet.
81
+ - **Typed `ContextBundle` dataclass** with `to_dict()` / `to_prompt_text()`
82
+ renderers. Frozen, JSON-serialisable, token-budgeted with source
83
+ attribution and an explicit `RedactionRecord` audit trail (R4).
84
+ - **Three-layer redaction** (`bcli.context._redact`) — composes the
85
+ existing `bcli/audit/_redact.py` key-based stripper, the
86
+ `bcli/telemetry/events.py` token-pattern regex, and a new URL
87
+ query-param / GUID / attachment scrubber (R5). Every redaction is
88
+ logged with a stable `rule_id` so regressions are catchable in CI.
89
+ - **Last-error capture** — central `BCLIError` handler now drops a
90
+ redacted snapshot to `~/.config/bcli/last-error.json`. **No
91
+ tracebacks by default**; `--debug` invocations also write a
92
+ `last-error-debug.json` sidecar at mode 0600 (R6).
93
+ - **`bcli.http` rolling tail** — opt-in NDJSON tail at
94
+ `~/.config/bcli/http-tail.ndjson` enabled by `[context] tail = true`.
95
+ Size-bounded via `RotatingFileHandler`; URLs are query-stripped on
96
+ read so the bundle stays safe.
97
+ - **`ContextConfig`** — new `[context]` config section with `tail`,
98
+ `redact_company_ids`, `attachment_max_bytes` knobs.
99
+
100
+ ## [0.4.0] — 2026-05-18 — Agent Interface Profile v0.1
101
+
102
+ The Agent Interface Profile (AIP) v0.1 lands: a small kernel of CLI
103
+ primitives that any agent runtime can drive deterministically, without
104
+ parallel schemas or hand-written MCP tools.
105
+
106
+ ### Added
107
+
108
+ - **`bcli describe --format json`** — canonical machine-readable
109
+ projection of the live Typer surface + endpoint registry + active
110
+ profile. One command MCP, completions, and docs all consume; new CLI
111
+ commands light up automatically. Cached at
112
+ `~/.config/bcli/describe/<profile>.<hash>.json` with mtime
113
+ invalidation. Subtree mode (`bcli describe get`, `bcli describe batch
114
+ run`) returns narrow output for token-constrained agents. Includes
115
+ forward-compat declarations: `emits_result_envelope`,
116
+ `emits_operation_state`, `requires_confirmation: "production"`, plus
117
+ the new `exit_codes` taxonomy and per-command `positionals` /
118
+ `required` / `limits` extensions.
119
+ - **Mutation result envelope (`--result-out PATH` / `--result-fd N`)**
120
+ on every mutating verb (`post`, `patch`, `delete`, `attach upload`,
121
+ `batch run`). Frozen 18-field JSON envelope written atomically
122
+ (`os.replace` + `fsync`); contains profile, environment, company,
123
+ method, endpoint, resolved URL, record id, status, exit code, BC
124
+ correlation id, started_at, duration_ms. Failed envelopes carry the
125
+ exit code (4 = not found, 6 = remote 4xx, 7 = remote 5xx, 8 = policy
126
+ refusal, etc.) so an agent can read it side-channel and act without
127
+ scraping stdout. For `batch run` the envelope's `record_id` is the
128
+ ledger run id — pivot directly to `bcli batch state <run-id>` for
129
+ per-step detail.
130
+ - **Batch operation ledger (SQLite)** — one
131
+ `~/.config/bcli/batch/<run-id>.db` per `bcli batch run` invocation.
132
+ WAL + `synchronous=NORMAL`, intent row written before each HTTP call
133
+ (survives SIGKILL); outcome row after. Derived run state
134
+ distinguishes `partially_committed` from a stale `running` stamp. New
135
+ commands: `bcli batch state <run-id>`, `bcli batch list [--state
136
+ STATE] [--limit N]`, `bcli batch rollback <run-id> [--dry-run]
137
+ [--yes]`. Rollback issues `DELETE` for committed POSTs only; PATCH /
138
+ DELETE marked `rollback_skipped` (no clean inverse without pre-image
139
+ snapshots). `disable_writes` is a hard refusal on rollback (no
140
+ `--yes` bypass).
141
+ - **Exit code taxonomy** — `bcli.exit_codes` defines 0/1/2/3/4/5/6/7/8
142
+ with short labels; `bcli describe` projects the map; centralized
143
+ error handler maps `BCLIError` subclasses (`AuthError → 3`,
144
+ `RegistryError → 4`, `ValidationError → 5`, `ConfigError → 2`,
145
+ `SafetyError → 8`).
146
+ - **"Did you mean" remediation hints** on `BCLIError` paths: auth →
147
+ `Run 'bcli auth login --profile X'`, config (no profiles) →
148
+ `Run 'bcli config init'`, config (unknown profile) → fuzzy match,
149
+ registry (no fuzzy) → `Run 'bcli registry import …'`.
150
+ - **JSON on pipe by default** — when stdout isn't a TTY and no
151
+ `--format` was passed, emit JSON. Pipelines, redirects, CI steps,
152
+ agent runtimes all get the canonical machine-readable shape with no
153
+ flag dance. The `CLAUDECODE` and `BCLI_AGENT` env hints keep their
154
+ markdown semantics (explicit user opt-in); legacy Windows console
155
+ host stays on markdown for the mojibake reason. `BCLI_FORMAT` and
156
+ explicit `--format` always win.
157
+ - **`--idempotency-key KEY`** on `post`, `patch`, `delete`, `attach
158
+ upload`. IETF `Idempotency-Key` HTTP header sent on the first call
159
+ (gateway-level dedup remains in play). Same-run replay protection in
160
+ `bcli batch run`: if two mutating steps share an `idempotency_key:`
161
+ in the YAML, the second is replayed (no second HTTP, no duplicate
162
+ ledger row), and the result entry carries `prior_seq`,
163
+ `prior_step_id`, `prior_bc_correlation_id`. Ledger schema migrates
164
+ v1 → v2 non-destructively via `ALTER TABLE step ADD COLUMN
165
+ idempotency_key`.
166
+ - **Progress events (`--progress-fd N`)** on `bcli batch run` and
167
+ `bcli extract run`. JSON-lines `step_started` / `step_completed`
168
+ written to a dedicated fd (separate from `--result-fd`). Stderr
169
+ stays human-readable; the fd channel is structured and stable for
170
+ agents to demux. Replayed steps emit a synthetic pair with
171
+ `status="replayed"` so the progress stream tells the truth.
172
+ - **23 dynamically-generated MCP tools** in `bcli_mcp` (was 4
173
+ hand-written). Server subprocesses `bcli describe` once on startup
174
+ and registers one tool per command; new CLI commands light up as
175
+ MCP tools automatically. Five new mutating tools (`bcli_post`,
176
+ `bcli_patch`, `bcli_delete`, `bcli_attach_upload`, `bcli_batch_run`)
177
+ pass `--result-out` and return the envelope as their tool result.
178
+ `status="failed"` envelopes surface as MCP `ToolError` with the BC
179
+ correlation id quoted.
180
+ - **`AsyncBCClient.delete_url(url, *, etag="*")`** — new SDK method
181
+ for absolute-URL deletes (used by the rollback path; avoids
182
+ re-resolving the registry at undo time).
183
+ - **`bcli skill install`** — generates `.claude/commands/bcli-<name>.md`
184
+ per saved query and per batch template (`~/.config/bcli/batches/
185
+ <profile>/*.yaml`). Generates a top-level
186
+ `.claude/skills/bcli/SKILL.md` index grouped by `categories:`.
187
+ SHA-256 content hash embedded in the provenance comment for
188
+ byte-stable idempotency — no `generated_at` timestamp, so re-runs on
189
+ unchanged sources are mtime-preserving no-ops. `manual: true` in a
190
+ file's YAML frontmatter protects it from regeneration. `--dry-run`
191
+ previews; `--target` resolves to explicit path > CWD with `.claude/`
192
+ > `$HOME`. Stdlib only — no jinja2; atomic writes via
193
+ `tempfile.mkstemp` + `os.replace`.
194
+ - **`bcli skill init`** — interactive wizard that reads `bcli describe
195
+ --format json` via subprocess, runs 4 Rich prompts (role / top-three
196
+ daily questions / slash-command style / generate-new-queries y/N),
197
+ fuzzy-matches existing saved queries against the top-three free
198
+ text (stdlib `difflib`), and proposes new role-tailored queries via
199
+ entry-point providers — each with a per-query `[y/N]` approval gate.
200
+ Generates `~/.claude/skills/bcli-<user>/SKILL.md` with YAML
201
+ provenance frontmatter. Atomic commit phase: snapshots existing
202
+ content, writes all targets, restores on first failure. Guardrails
203
+ via `_assert_writable` restrict writes to `~/.config/bcli/queries/`,
204
+ `~/.claude/skills/bcli-<user>/`, and `~/.config/bcli/skills/`;
205
+ symlink-safe via `Path.resolve(strict=False)` + `is_relative_to`.
206
+ - **`bcli skill update`** — idempotent re-run via state cache at
207
+ `~/.config/bcli/skills/.last-init.json`. The cache persists both
208
+ the interview answers AND the approved-query bodies so a later
209
+ `--non-interactive` replay re-writes the same queries verbatim
210
+ (without re-asking the operator). Describe-payload-hash mismatch
211
+ refuses silent replay and asks for a re-interview when the describe
212
+ surface changed under the user's feet.
213
+ - **Saved-query YAML schema extension** — three additive fields
214
+ (`description`, `categories`, `args`). Existing saved-query bundles
215
+ without these still work: when `args:` is omitted, `bcli skill
216
+ install` derives it from `params:` keys (required first, optional
217
+ second, both in YAML insertion order). Documented in
218
+ `docs/saved-queries.md`'s new "Slash-command projection" section.
219
+ - **Entry-point group `bcli.skill_init.role_templates`** — OSS bcli
220
+ ships with an opinion-free default proposer (returns `[]` for every
221
+ role). Downstream packages plug in role templates by registering
222
+ callables under this entry-point group via standard Python
223
+ packaging. Discovered at wizard time via
224
+ `importlib.metadata.entry_points`. The provider signature is
225
+ `(interview, payload) -> list[ProposedQuery]`; downstream
226
+ integrators publish their own integration documentation.
227
+
228
+ ### Changed
229
+
230
+ - **Policy refusal exit code 1 → 8.** Scripts that grep `if exit==1`
231
+ for "the read-only profile blocked me" need updating. Agents
232
+ consuming `bcli describe`'s new `exit_codes` field pick up the new
233
+ code automatically.
234
+ - **MCP tool renames** (breaking for existing MCP clients — Claude
235
+ Desktop, MCP Inspector configs referencing the old names need an
236
+ update):
237
+ - `query` → `bcli_get`
238
+ - `list_endpoints` → `bcli_endpoint_list`
239
+ - `describe_endpoint` → `bcli_endpoint_info` (with
240
+ `bcli_endpoint_fields` split out for field discovery)
241
+ - `list_companies` → `bcli_company_list`
242
+
243
+ Migration table in `docs/mcp-server.md`. Tool names now consistently
244
+ match the CLI command path.
245
+ - **MCP `bcli_get --top` cap remains 50 default / 1000 max** — parity
246
+ with the pre-rewrite hand-written `query` tool. CLI shell users can
247
+ still pass `--top 100000` directly; the cap is enforced only at the
248
+ MCP schema level (advisory for agent runtimes).
249
+ - **Stderr routing for `bcli batch run` metadata** — the ledger path
250
+ and run id print to stderr, not stdout. Stdout matches legacy batch
251
+ output byte-for-byte (required by the additive constraint).
252
+
253
+ ### Fixed
254
+
255
+ - **Clean SIGPIPE handling for piped output** — `bcli <cmd> | head`,
256
+ `| grep -m 1`, and similar pipe-truncating consumers now terminate
257
+ the CLI silently, matching `cat` and `grep` conventions, instead of
258
+ emitting a `BrokenPipeError: [Errno 32] Broken pipe` traceback at
259
+ interpreter shutdown. Implemented as a new `bcli_cli.app:main`
260
+ console-script entry point that installs `SIGPIPE -> SIG_DFL` on
261
+ POSIX with a `BrokenPipeError` safety net for Windows.
262
+ - **Hyphenated saved-query param names** — the workflow template
263
+ resolver now accepts hyphens in identifiers, so references like
264
+ `${{ params.vendor-no }}` substitute correctly. Previously the regex
265
+ matched only `[\w.]`, silently leaving the literal `${{ … }}` token
266
+ in the rendered filter (BC then 400'd or, worse, returned mismatched
267
+ rows). Affects both `bcli q` saved queries and `bcli batch`
268
+ workflows.
269
+
270
+ ### Breaking changes
271
+
272
+ The two items above (exit code 1→8 + MCP tool renames) are intentional
273
+ breaking changes called out in the AIP plan. Both have one-line
274
+ migration paths. Skill install / skill init / skill update are
275
+ additive — no breaking changes from the Skills layer.
276
+
277
+ ### Deferred to v0.5
278
+
279
+ - **Cross-run idempotency replay** — would require scanning every
280
+ `*.db` in `~/.config/bcli/batch/` on each mutating call. Same-run
281
+ protection covers the agent-retry case which is the common one;
282
+ gateway-level Idempotency-Key dedup covers the rest.
283
+ - **`batch run --idempotency-key`** as a run-level flag — collides
284
+ across multiple mutating steps. Per-step `idempotency_key:` in the
285
+ batch YAML is the correct surface.
286
+ - **`telemetry_event_id` / `audit_log_offset` on the envelope** —
287
+ currently always `null`. Wiring requires extending the
288
+ `TelemetrySink` and audit protocols to return the emitted event id /
289
+ log offset, touching every backend including the optional Azure
290
+ Monitor extra.
291
+ - **Plan-token binding for single mutations** — `batch run --plan-out`
292
+ works; `bcli post --plan-out` does not. Defer until requested.
293
+ - **Direct FastMCP schema-introspection test** — the `__signature__`
294
+ patch is indirectly covered via tool-list registration tests; a
295
+ future FastMCP upgrade could silently degrade tool input schemas
296
+ without breaking tests.
297
+ - **Etag capture in ledger** — rollback DELETEs use `etag="*"`. A
298
+ future concurrent edit between POST and rollback could clobber.
299
+ - **CWD-relative batch template discovery** for `bcli skill install` —
300
+ today only `~/.config/bcli/batches/<profile>/*.yaml` is scanned;
301
+ project-local batches in `./batches/` would also be useful for the
302
+ per-project `.claude/` workflow.
303
+ - **SKILL.md frontmatter `generated_at` churn cleanup** — the
304
+ timestamp ticks forward on every `bcli skill update
305
+ --non-interactive` replay, so the frontmatter changes even when the
306
+ body is byte-stable. Idempotency tests compare body-only; downstream
307
+ content-hash watchers would see noise. Cosmetic.
308
+ - **`bcli skill update` separated from `init`** — today
309
+ `update_command` delegates to `init_command(...)` verbatim.
310
+ Documented for future evolution.
311
+ - **Public `bcli.skill_init` namespace for the entry-point contract**
312
+ — downstream packages currently couple to
313
+ `bcli_cli.commands.skill_init_cmd` for `InterviewState` /
314
+ `ProposedQuery`. A future release could promote the protocol types
315
+ to a public `bcli.skill_init` namespace.
316
+
317
+ ## [0.2.0] — 2026-05-06
318
+
319
+ ### Added
320
+
321
+ - **Structured `--dry-run` output** — write commands (`post`, `patch`,
322
+ `delete`, `attach upload`) now emit a stable JSON envelope on stdout
323
+ when `--format json` / `ndjson` / `raw` is selected. Includes
324
+ `dry_run`, `method`, `endpoint`, `resolved_url`, `profile`,
325
+ `environment`, `company_id`, `body`, and `record_id` (when applicable).
326
+ Agents can parse the envelope before deciding whether to proceed. The
327
+ human format keeps the same yellow rich panel on stderr but is now
328
+ augmented with the resolved URL and profile context. See
329
+ `docs/write-operations.md`.
330
+ - **Opt-in audit log** — new `[audit]` config section persists every
331
+ write to a per-profile JSONL file. Each entry captures the resolved
332
+ URL, response status, BC `correlation_id`, latency, redacted request
333
+ body, and outcome (`completed` / `failed` / `dry_run`). Bounded disk
334
+ usage via single-backup rotation. SDK (`AsyncBCClient`) does NOT
335
+ auto-emit; this is a CLI-layer ergonomic on top of BC permission sets.
336
+ See `docs/configuration.md#audit-log`.
337
+ - **Endpoint `caution` flag** — `EndpointMetadata` now carries a
338
+ `caution: low | medium | high` level. Importers populate it
339
+ automatically from a verb-name heuristic (entities containing `post`,
340
+ `release`, `cancel`, `void`, `reverse`, `apply`, `unapply` are flagged
341
+ `high`). Surfaced in `bcli endpoint info` and the `list_endpoints` MCP
342
+ tool so agents can require explicit user confirmation before mutating
343
+ posted/closed records.
344
+ - New `AGENTS.md` recipes for dry-run-first writes, caution-level
345
+ interpretation, and audit-log location.
346
+
347
+ ## [0.1.5] — 2026-05-05
348
+
349
+ ### Added
350
+
351
+ - **Business Central admin setup guide** — new
352
+ `docs/business-central-admin-setup.md` walks a zero-knowledge user
353
+ through Entra app registration, localhost redirect setup, delegated BC
354
+ permissions, admin consent, BC user permission sets, first `bcli
355
+ config init`, and verification.
356
+ - **`bcli-mcp` preview server** — an MCP (Model Context Protocol) server
357
+ that lets Claude Desktop and other MCP clients drive bcli. Four
358
+ read-only tools: `query`, `list_endpoints`, `describe_endpoint`,
359
+ `list_companies`. Subprocess-only architecture inherits profile, auth,
360
+ retry, telemetry, and `disable_writes` from the CLI. Install with
361
+ `pip install "bc-cli[mcp]"`. See `docs/mcp-server.md`.
362
+
363
+ ### Changed
364
+
365
+ - `bcli config init` now defaults to browser PKCE auth for local humans
366
+ and agents. New `--automation` and `--headless` shortcuts create
367
+ client-credentials and device-code profiles respectively.
368
+ - CLI runtime dependencies now ship with the base `bc-cli` install, so
369
+ `pip install bc-cli` and `uv tool install bc-cli` provide a working
370
+ `bcli` command without requiring an extra.
371
+ - `bcli company list` accepts `--format` (`json`, `markdown`, `csv`,
372
+ `ndjson`, `table`). Stable JSON shape:
373
+ `[{"id", "name", "alias", "is_default"}]`.
374
+ - `bcli endpoint list` and `bcli endpoint info` accept `--format json`.
375
+ Stable JSON shapes documented inline in each command's help text.
376
+
377
+ ### Removed
378
+
379
+ - Removed WorkOS AuthKit support. Browser PKCE is now the delegated auth
380
+ path, Business Central remains the permission boundary, and
381
+ client-credentials profiles cover automation.
382
+
383
+ ## [0.1.2] — 2026-04-29
384
+
385
+ Security release. Closes four findings from a strix.ai run against the
386
+ repo. No public SDK signature changes; the CLI gains one new flag
387
+ (`bcli batch run --yes`).
388
+
389
+ ### Security
390
+
391
+ - **vuln-0001 (HIGH, CWE-352)** — WorkOS localhost callback now binds a
392
+ per-login high-entropy `state` token. Before this release, any local
393
+ request reaching `127.0.0.1:8401/callback?code=…` during the login
394
+ window would be exchanged for a role-bearing WorkOS identity and
395
+ cached on disk. The handler now rejects callbacks whose path is not
396
+ `/callback` (404) or whose `state` doesn't match the per-login token
397
+ (400), and surfaces invalid callbacks as auth failures rather than
398
+ masking them as timeouts.
399
+ - **vuln-0002 (MEDIUM, CWE-841)** — `bcli batch run` now enforces the
400
+ `disable_writes` profile gate that direct `post`/`patch`/`delete`
401
+ commands already honour. Mutating batch steps on a read-only profile
402
+ prompt for confirmation interactively or abort with exit 1 in
403
+ non-interactive sessions. New `--yes` / `-y` flag opts scripted use
404
+ past the prompt. Pure GET batches are unaffected, and `--dry-run`
405
+ still skips the gate so workflows can be previewed.
406
+ - **vuln-0003 (MEDIUM)** — Browser auth callback listener now binds an
407
+ ephemeral kernel-assigned port instead of a hard-coded 8400, and
408
+ serves continuously until a state-bound callback arrives or the
409
+ timeout expires. Stray requests (e.g. `/favicon.ico`) and
410
+ state-mismatched callbacks no longer consume the only callback slot.
411
+ Microsoft Entra accepts any port for `http://localhost` redirect URIs
412
+ on public clients per RFC 8252, so existing app registrations
413
+ continue to work without changes.
414
+ - **vuln-0004 (HIGH, CWE-841)** — `SafeContext` writes are now bound to
415
+ the explicit `environment` and `company_id` passed to
416
+ `client.safe_write(env, company)`, not the client's profile-bound
417
+ target. Previously the safety gate validated operator intent but the
418
+ underlying URL still resolved against the profile, so writes inside
419
+ `safe_write("Sandbox", "company-SANDBOX")` could still hit
420
+ `Production/company-PROD`. Closes the documentation-vs-behaviour
421
+ mismatch where the README/changelog claimed the gate prevented
422
+ wrong-environment writes.
423
+
424
+ ### Changed
425
+
426
+ - `bcli batch run` accepts a new `--yes` / `-y` flag (see vuln-0002
427
+ above). Existing automation against writable profiles is unaffected;
428
+ CI scripts that run mutating batches against a `disable_writes`
429
+ profile must pass `--yes` or migrate to a writable profile.
430
+
431
+ ## [0.1.1] — 2026-04-29
432
+
433
+ OSS-readiness polish. No SDK behaviour changes; one CLI rename and a
434
+ README/docstring cleanup pass.
435
+
436
+ ### Changed
437
+
438
+ - **Renamed the document-attachment CLI command** to `bcli attach`,
439
+ with subcommands `bcli attach upload` and `bcli attach test`.
440
+ Functionality is unchanged. The previous name was a customer-name
441
+ leftover from internal development; the workflow is generic to any
442
+ Business Central tenant.
443
+ - Genericised customer-named example values in
444
+ `docs/authentication.md`, `examples/attach-purchase-invoice-pdf.yaml`,
445
+ and SDK docstrings.
446
+
447
+ ### Fixed
448
+
449
+ - README license badge said Apache 2.0 but the License section said
450
+ MIT. Now consistent: Apache 2.0 throughout (matches the actual
451
+ `LICENSE` file and `pyproject.toml`).
452
+
453
+ ## [0.1.0] — 2026-04-29
454
+
455
+ First public release on PyPI as **`bc-cli`**.
456
+
457
+ > **Note on the package name.** The PyPI distribution name is `bc-cli`,
458
+ > not `bcli` — the latter is squatted by an unrelated 2018-era
459
+ > "EC2 Cluster Creator" package. The Python import name (`import bcli`)
460
+ > and the CLI binary on PATH (`bcli`) are unaffected.
461
+
462
+ ### Added
463
+
464
+ - **SDK** — `BCClient` (sync) and `AsyncBCClient` (async) for Microsoft
465
+ Dynamics 365 Business Central. Two construction modes: profile-based
466
+ (TOML config files) and programmatic (pass auth params directly).
467
+ - **CLI** — Typer-based `bcli` command with subcommands for query
468
+ (`get`), write (`post`/`patch`/`delete`/`attach`), config, auth,
469
+ registry import, batch operations, saved queries (`q`), and ETL
470
+ pipelines.
471
+ - **Three-tier endpoint resolution.** Custom registry → standard v2.0 →
472
+ fuzzy-match suggestion. Custom APIs imported from Postman v2.1
473
+ collections, raw JSON, or live `$metadata`.
474
+ - **Auth** — Client-credentials, device-code, browser (PKCE), and
475
+ WorkOS AuthKit (role → BC client_id mapping). Token cache with 5-min
476
+ expiry buffer; OS keychain integration via `keyring`.
477
+ - **Write safety** — `SafeContext` gate enforces explicit `environment`
478
+ + `company_id` on writes; production writes require
479
+ `confirm_production=True`. CLI's `disable_writes` profile flag adds
480
+ an interactive confirmation prompt before any mutating call.
481
+ - **Saved queries** (`bcli q`) — Hide OData syntax behind named,
482
+ parameterised aliases stored per-profile. Per-param `type`,
483
+ `pattern`, `min`/`max`, and `enum` validation runs locally before any
484
+ HTTP call. String parameters interpolated into `filter:` are escaped
485
+ using OData v4 single-quote rules so an injection-shaped value cannot
486
+ break the literal.
487
+ - **ETL pipeline** — Built-in [dlt](https://dlthub.com) source for
488
+ incremental backup. Polaris REST catalog integration for Iceberg
489
+ snapshots. Generic + bcli-bridge layers.
490
+ - **Telemetry** — Pluggable backend with `null`, `console`,
491
+ `azure_monitor`, and arbitrary `module:Class` sinks. Privacy-first
492
+ defaults: token redaction in error messages, opt-in capture of filter
493
+ text and signed-in UPN. Every event carries `version`, `os`,
494
+ `os_release`, `arch`, `python_version`, and a stable per-laptop
495
+ `install_id` for downstream slicing.
496
+ - **Structured logging** — JSON request logs to the `bcli.http` logger
497
+ with method/url/status/retry-count/latency/correlation-id.
498
+
499
+ ### Security
500
+
501
+ The 0.1.0 release went through two independent security review passes
502
+ before publish. Findings addressed:
503
+
504
+ - Pinned wheel-version installer scripts; scrubbed registry `supports`
505
+ arrays to `["GET"]` for read-only profiles; removed sensitive field
506
+ metadata from public artefacts shipped by the bootstrap installer.
507
+ - **Critical:** Project-level `.bcli.toml` files cannot override
508
+ `[telemetry] backend`. Closes an arbitrary-Python-import RCE on
509
+ `bcli` invocation in any directory containing a malicious
510
+ `.bcli.toml`.
511
+ - **High:** Token caches and identity caches written with `0o600`
512
+ perms via atomic write; parent dir tightened to `0o700`; one-shot
513
+ warning on insecure existing perms.
514
+ - **High:** WorkOS role cache now expires after 1 hour; revoked roles
515
+ no longer keep mapping to privileged BC apps indefinitely.
516
+ - **Medium:** Absolute-URL paths (`@odata.nextLink`) validated against
517
+ a `*.businesscentral.dynamics.com` / `*.bc.dynamics.com` host
518
+ allowlist before the bearer token is attached. Closes a
519
+ bearer-exfiltration vector via tampered BC responses.
520
+ - **Medium:** CI hardened — third-party actions pinned by full commit
521
+ SHA, default `permissions: contents: read`, `uv sync --locked` for
522
+ reproducible installs from a committed `uv.lock`.
523
+ - **Medium:** Saved-query OData injection prevention (filter-context
524
+ escape + per-parameter `type`/`pattern`/`min`/`max`/`enum`
525
+ validation).
526
+
527
+ ### Known limitations
528
+
529
+ - Alpha software. The SDK and CLI surface may change in 0.x releases;
530
+ track this CHANGELOG for breaking changes.
531
+ - Some BC custom-API edge cases (zero-GUID ids on
532
+ `SourceTableTemporary` pages) require the `--standard` flag to
533
+ bypass the registry — see `bcli attach upload --help`.
534
+
535
+ ## [Pre-0.1.0 history]
536
+
537
+ Earlier development happened under the working name `bcapi`, then
538
+ moved to `bcli` (April 2026), then to the PyPI distribution name
539
+ `bc-cli` (April 2026, after discovering the `bcli` PyPI name was
540
+ squatted by an unrelated 2018 package).
541
+
542
+ [Unreleased]: https://github.com/igor-ctrl/bcli/compare/v0.4.0...HEAD
543
+ [0.4.0]: https://github.com/igor-ctrl/bcli/compare/v0.2.0...v0.4.0
544
+ [0.2.0]: https://github.com/igor-ctrl/bcli/compare/v0.1.5...v0.2.0
545
+ [0.1.5]: https://github.com/igor-ctrl/bcli/compare/v0.1.2...v0.1.5
546
+ [0.1.2]: https://github.com/igor-ctrl/bcli/compare/v0.1.1...v0.1.2
547
+ [0.1.1]: https://github.com/igor-ctrl/bcli/compare/v0.1.0...v0.1.1
548
+ [0.1.0]: https://github.com/igor-ctrl/bcli/releases/tag/v0.1.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bc-cli
3
- Version: 0.3.0
3
+ Version: 0.5.0
4
4
  Summary: Python SDK and CLI for Microsoft Dynamics 365 Business Central APIs
5
5
  Project-URL: Homepage, https://github.com/igor-ctrl/bcli
6
6
  Project-URL: Repository, https://github.com/igor-ctrl/bcli
@@ -30,6 +30,13 @@ Requires-Dist: pyyaml>=6.0
30
30
  Requires-Dist: rich>=13.0
31
31
  Requires-Dist: tomlkit>=0.13
32
32
  Requires-Dist: typer>=0.12
33
+ Provides-Extra: ask
34
+ Requires-Dist: anthropic>=0.40; extra == 'ask'
35
+ Requires-Dist: openai>=1.50; extra == 'ask'
36
+ Provides-Extra: ask-claude
37
+ Requires-Dist: anthropic>=0.40; extra == 'ask-claude'
38
+ Provides-Extra: ask-openai
39
+ Requires-Dist: openai>=1.50; extra == 'ask-openai'
33
40
  Provides-Extra: cli
34
41
  Provides-Extra: dev
35
42
  Requires-Dist: anthropic>=0.40; extra == 'dev'
@@ -0,0 +1,46 @@
1
+ # bcli-site
2
+
3
+ Astro + Tailwind landing site for [bcli](https://github.com/igor-ctrl/bcli).
4
+ Single page (v0): hero + install + example commands + features.
5
+
6
+ ## Development
7
+
8
+ ```bash
9
+ cd bcli-site/
10
+ corepack enable # ensures pnpm is on PATH
11
+ pnpm install # one-time
12
+ pnpm dev # http://localhost:4321
13
+ pnpm build # static output → dist/
14
+ pnpm preview # preview the built site
15
+ ```
16
+
17
+ ## Deploy
18
+
19
+ Intended target is Vercel; the project root in Vercel should be set
20
+ to `bcli-site/`. The GH workflow at `.github/workflows/site.yml`
21
+ performs a build + (commented-out) deploy step — uncomment and add
22
+ `VERCEL_TOKEN` + `VERCEL_PROJECT_ID` + `VERCEL_ORG_ID` to the repo
23
+ secrets to enable auto-deploy from `main`.
24
+
25
+ ## Structure
26
+
27
+ ```
28
+ bcli-site/
29
+ astro.config.mjs # Astro + Tailwind
30
+ tailwind.config.mjs # palette + fonts (matches the terminal-y bcli vibe)
31
+ tsconfig.json # extends astro/tsconfigs/strict
32
+ src/
33
+ pages/index.astro # hero + install + 3 examples + feature grid
34
+ components/
35
+ Hero.astro
36
+ CodeBlock.astro
37
+ styles/global.css # Tailwind base + small layer overrides
38
+ public/
39
+ og.png.placeholder # TODO: real OG card
40
+ ```
41
+
42
+ ## Content rules (matches Part 3 / R9)
43
+
44
+ The copy must describe what's actually shipped — packs, ask, MCP
45
+ server, describe. Do NOT oversell the `bcli agent` mode (deferred
46
+ to Part 4). Once the agent loop lands, add a section here.
@@ -0,0 +1,14 @@
1
+ ---
2
+ interface Props {
3
+ caption?: string;
4
+ lang?: string;
5
+ }
6
+ const { caption, lang = "bash" } = Astro.props;
7
+ ---
8
+
9
+ <figure class="my-6">
10
+ {caption && (
11
+ <figcaption class="text-sm text-muted mb-2">{caption}</figcaption>
12
+ )}
13
+ <pre class="rounded-lg bg-black/40 border border-white/10 p-4 text-sm leading-relaxed overflow-x-auto"><code data-lang={lang}><slot /></code></pre>
14
+ </figure>
@@ -0,0 +1,32 @@
1
+ ---
2
+ // Hero — first impression, tagline, install one-liner.
3
+ ---
4
+
5
+ <section class="container-wide pt-24 pb-16">
6
+ <p class="text-sm uppercase tracking-widest text-accent2">
7
+ bcli — Business Central CLI &amp; SDK
8
+ </p>
9
+ <h1 class="mt-3 text-4xl md:text-6xl font-semibold tracking-tight leading-tight">
10
+ Business Central from the terminal.<br />
11
+ <span class="text-accent">Designed for humans and AI agents.</span>
12
+ </h1>
13
+ <p class="mt-6 max-w-2xl text-lg text-muted leading-relaxed">
14
+ A discovery-first command line and Python SDK for Microsoft Dynamics 365
15
+ Business Central. Reusable packs, second-opinion oracle, and an MCP server
16
+ so every agent runtime can drive it deterministically.
17
+ </p>
18
+ <div class="mt-8 flex flex-col sm:flex-row gap-4">
19
+ <a
20
+ href="#install"
21
+ class="rounded-md bg-accent text-ink font-medium px-5 py-3 hover:opacity-90 transition"
22
+ >
23
+ Install
24
+ </a>
25
+ <a
26
+ href="https://github.com/igor-ctrl/bcli"
27
+ class="rounded-md border border-white/15 px-5 py-3 hover:bg-white/5 transition"
28
+ >
29
+ View on GitHub
30
+ </a>
31
+ </div>
32
+ </section>