agent-devkit 0.1.6 → 0.2.0

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 (551) hide show
  1. package/README.md +13 -1
  2. package/package.json +1 -1
  3. package/runtime/README.md +53 -1
  4. package/runtime/agent +5 -0
  5. package/runtime/agents/README.md +26 -0
  6. package/runtime/agents/agent-devkit-agent-builder/AGENTS.md +24 -0
  7. package/runtime/agents/agent-devkit-agent-builder/README.md +37 -0
  8. package/runtime/agents/agent-devkit-agent-builder/agent.yaml +46 -0
  9. package/runtime/agents/agent-devkit-agent-builder/capabilities/plan-agent/capability.yaml +29 -0
  10. package/runtime/agents/agent-devkit-agent-builder/capabilities/plan-agent/decision-rules.md +7 -0
  11. package/runtime/agents/agent-devkit-agent-builder/capabilities/plan-agent/runner.py +33 -0
  12. package/runtime/agents/agent-devkit-agent-builder/capabilities/plan-agent/workflow.md +8 -0
  13. package/runtime/agents/agent-devkit-agent-builder/capabilities/scaffold-agent/capability.yaml +31 -0
  14. package/runtime/agents/agent-devkit-agent-builder/capabilities/scaffold-agent/decision-rules.md +9 -0
  15. package/runtime/agents/agent-devkit-agent-builder/capabilities/scaffold-agent/runner.py +39 -0
  16. package/runtime/agents/agent-devkit-agent-builder/capabilities/scaffold-agent/workflow.md +8 -0
  17. package/runtime/agents/agent-devkit-agent-builder/capabilities/validate-agent-contract/capability.yaml +28 -0
  18. package/runtime/agents/agent-devkit-agent-builder/capabilities/validate-agent-contract/decision-rules.md +6 -0
  19. package/runtime/agents/agent-devkit-agent-builder/capabilities/validate-agent-contract/runner.py +33 -0
  20. package/runtime/agents/agent-devkit-agent-builder/capabilities/validate-agent-contract/workflow.md +7 -0
  21. package/runtime/agents/agent-devkit-agent-builder/infra/integrations/agent-devkit/agent_builder_repository.py +527 -0
  22. package/runtime/agents/agent-devkit-agent-builder/knowledge/context.md +15 -0
  23. package/runtime/agents/agent-devkit-agent-builder/knowledge/policies.yaml +11 -0
  24. package/runtime/agents/agent-devkit-agent-builder/knowledge/system.md +11 -0
  25. package/runtime/agents/agent-devkit-agent-builder/templates/agent-plan-output.md +20 -0
  26. package/runtime/agents/agent-devkit-agent-builder/templates/scaffold-plan-output.md +13 -0
  27. package/runtime/agents/agent-devkit-agent-builder/templates/validation-report-output.md +13 -0
  28. package/runtime/agents/agent-devkit-agent-builder/tests/test_runners.py +188 -0
  29. package/runtime/agents/automation-architect/AGENTS.md +11 -0
  30. package/runtime/agents/automation-architect/README.md +27 -0
  31. package/runtime/agents/automation-architect/agent.yaml +57 -0
  32. package/runtime/agents/automation-architect/capabilities/classify-automation-request/capability.yaml +35 -0
  33. package/runtime/agents/automation-architect/capabilities/classify-automation-request/decision-rules.md +10 -0
  34. package/runtime/agents/automation-architect/capabilities/classify-automation-request/runner.py +37 -0
  35. package/runtime/agents/automation-architect/capabilities/classify-automation-request/workflow.md +7 -0
  36. package/runtime/agents/automation-architect/capabilities/delegate-automation-build/capability.yaml +34 -0
  37. package/runtime/agents/automation-architect/capabilities/delegate-automation-build/decision-rules.md +7 -0
  38. package/runtime/agents/automation-architect/capabilities/delegate-automation-build/runner.py +37 -0
  39. package/runtime/agents/automation-architect/capabilities/delegate-automation-build/workflow.md +6 -0
  40. package/runtime/agents/automation-architect/capabilities/plan-automation-solution/capability.yaml +35 -0
  41. package/runtime/agents/automation-architect/capabilities/plan-automation-solution/decision-rules.md +7 -0
  42. package/runtime/agents/automation-architect/capabilities/plan-automation-solution/runner.py +37 -0
  43. package/runtime/agents/automation-architect/capabilities/plan-automation-solution/workflow.md +7 -0
  44. package/runtime/agents/automation-architect/capabilities/review-automation-solution/capability.yaml +36 -0
  45. package/runtime/agents/automation-architect/capabilities/review-automation-solution/decision-rules.md +7 -0
  46. package/runtime/agents/automation-architect/capabilities/review-automation-solution/runner.py +39 -0
  47. package/runtime/agents/automation-architect/capabilities/review-automation-solution/workflow.md +7 -0
  48. package/runtime/agents/automation-architect/infra/integrations/automation-architecture/automation_architecture_repository.py +481 -0
  49. package/runtime/agents/automation-architect/knowledge/context.md +22 -0
  50. package/runtime/agents/automation-architect/knowledge/policies.yaml +20 -0
  51. package/runtime/agents/automation-architect/knowledge/system.md +8 -0
  52. package/runtime/agents/automation-architect/templates/automation-classification.md +6 -0
  53. package/runtime/agents/automation-architect/templates/automation-plan.md +5 -0
  54. package/runtime/agents/automation-architect/tests/test_runners.py +135 -0
  55. package/runtime/agents/aws-architecture-analyst/agent.yaml +17 -4
  56. package/runtime/agents/aws-cloudwatch-log-analyzer/agent.yaml +12 -2
  57. package/runtime/agents/aws-cloudwatch-log-analyzer/capabilities/analyze-service-error/capability.yaml +16 -0
  58. package/runtime/agents/aws-lambda-builder/AGENTS.md +27 -0
  59. package/runtime/agents/aws-lambda-builder/README.md +21 -0
  60. package/runtime/agents/aws-lambda-builder/agent.yaml +46 -0
  61. package/runtime/agents/aws-lambda-builder/capabilities/deploy-lambda-plan/capability.yaml +18 -0
  62. package/runtime/agents/aws-lambda-builder/capabilities/deploy-lambda-plan/decision-rules.md +6 -0
  63. package/runtime/agents/aws-lambda-builder/capabilities/deploy-lambda-plan/runner.py +33 -0
  64. package/runtime/agents/aws-lambda-builder/capabilities/deploy-lambda-plan/workflow.md +6 -0
  65. package/runtime/agents/aws-lambda-builder/capabilities/generate-lambda-project/capability.yaml +20 -0
  66. package/runtime/agents/aws-lambda-builder/capabilities/generate-lambda-project/decision-rules.md +6 -0
  67. package/runtime/agents/aws-lambda-builder/capabilities/generate-lambda-project/runner.py +39 -0
  68. package/runtime/agents/aws-lambda-builder/capabilities/generate-lambda-project/workflow.md +7 -0
  69. package/runtime/agents/aws-lambda-builder/capabilities/package-lambda/capability.yaml +22 -0
  70. package/runtime/agents/aws-lambda-builder/capabilities/package-lambda/decision-rules.md +6 -0
  71. package/runtime/agents/aws-lambda-builder/capabilities/package-lambda/runner.py +41 -0
  72. package/runtime/agents/aws-lambda-builder/capabilities/package-lambda/workflow.md +6 -0
  73. package/runtime/agents/aws-lambda-builder/capabilities/plan-lambda/capability.yaml +18 -0
  74. package/runtime/agents/aws-lambda-builder/capabilities/plan-lambda/decision-rules.md +7 -0
  75. package/runtime/agents/aws-lambda-builder/capabilities/plan-lambda/runner.py +33 -0
  76. package/runtime/agents/aws-lambda-builder/capabilities/plan-lambda/workflow.md +6 -0
  77. package/runtime/agents/aws-lambda-builder/capabilities/review-lambda-security/capability.yaml +18 -0
  78. package/runtime/agents/aws-lambda-builder/capabilities/review-lambda-security/decision-rules.md +7 -0
  79. package/runtime/agents/aws-lambda-builder/capabilities/review-lambda-security/runner.py +33 -0
  80. package/runtime/agents/aws-lambda-builder/capabilities/review-lambda-security/workflow.md +5 -0
  81. package/runtime/agents/aws-lambda-builder/infra/integrations/aws-lambda/aws_lambda_repository.py +688 -0
  82. package/runtime/agents/aws-lambda-builder/knowledge/context.md +12 -0
  83. package/runtime/agents/aws-lambda-builder/knowledge/policies.yaml +23 -0
  84. package/runtime/agents/aws-lambda-builder/knowledge/system.md +10 -0
  85. package/runtime/agents/aws-lambda-builder/templates/lambda-deploy-plan.md +3 -0
  86. package/runtime/agents/aws-lambda-builder/templates/lambda-package.md +3 -0
  87. package/runtime/agents/aws-lambda-builder/templates/lambda-plan.md +3 -0
  88. package/runtime/agents/aws-lambda-builder/templates/lambda-readme.md +3 -0
  89. package/runtime/agents/aws-lambda-builder/templates/lambda-security-review.md +3 -0
  90. package/runtime/agents/aws-lambda-builder/tests/test_runners.py +355 -0
  91. package/runtime/agents/aws-operations-operator/agent.yaml +18 -6
  92. package/runtime/agents/aws-security-governance-auditor/agent.yaml +17 -5
  93. package/runtime/agents/azure-devops-orchestrator/agent.yaml +15 -2
  94. package/runtime/agents/azure-devops-orchestrator/capabilities/read-card/capability.yaml +29 -0
  95. package/runtime/agents/bpo-analyser/agent.yaml +12 -2
  96. package/runtime/agents/bpo-analyser/knowledge/policies.yaml +2 -2
  97. package/runtime/agents/data-scientist-analyst/agent.yaml +16 -4
  98. package/runtime/agents/data-scientist-analyst/capabilities/generate-data-report/capability.yaml +1 -1
  99. package/runtime/agents/data-scientist-analyst/capabilities/generate-reconciliation-report/capability.yaml +1 -1
  100. package/runtime/agents/data-scientist-analyst/capabilities/run-data-pipeline/capability.yaml +1 -1
  101. package/runtime/agents/data-scientist-analyst/infra/integrations/agent-bridge/methods/analyze-sql-source.yaml +1 -1
  102. package/runtime/agents/data-scientist-analyst/knowledge/policies.yaml +4 -4
  103. package/runtime/agents/data-scientist-analyst/knowledge/system.md +1 -1
  104. package/runtime/agents/data-scientist-analyst/tests/test_runners.py +1 -1
  105. package/runtime/agents/database-change-operator/agent.yaml +12 -1
  106. package/runtime/agents/docker-container-builder/AGENTS.md +27 -0
  107. package/runtime/agents/docker-container-builder/README.md +21 -0
  108. package/runtime/agents/docker-container-builder/agent.yaml +52 -0
  109. package/runtime/agents/docker-container-builder/capabilities/analyze-containerization-target/capability.yaml +18 -0
  110. package/runtime/agents/docker-container-builder/capabilities/analyze-containerization-target/decision-rules.md +6 -0
  111. package/runtime/agents/docker-container-builder/capabilities/analyze-containerization-target/runner.py +32 -0
  112. package/runtime/agents/docker-container-builder/capabilities/analyze-containerization-target/workflow.md +6 -0
  113. package/runtime/agents/docker-container-builder/capabilities/generate-compose/capability.yaml +18 -0
  114. package/runtime/agents/docker-container-builder/capabilities/generate-compose/decision-rules.md +7 -0
  115. package/runtime/agents/docker-container-builder/capabilities/generate-compose/runner.py +32 -0
  116. package/runtime/agents/docker-container-builder/capabilities/generate-compose/workflow.md +6 -0
  117. package/runtime/agents/docker-container-builder/capabilities/generate-container-project-files/capability.yaml +20 -0
  118. package/runtime/agents/docker-container-builder/capabilities/generate-container-project-files/decision-rules.md +7 -0
  119. package/runtime/agents/docker-container-builder/capabilities/generate-container-project-files/runner.py +38 -0
  120. package/runtime/agents/docker-container-builder/capabilities/generate-container-project-files/workflow.md +7 -0
  121. package/runtime/agents/docker-container-builder/capabilities/generate-dockerfile/capability.yaml +18 -0
  122. package/runtime/agents/docker-container-builder/capabilities/generate-dockerfile/decision-rules.md +6 -0
  123. package/runtime/agents/docker-container-builder/capabilities/generate-dockerfile/runner.py +32 -0
  124. package/runtime/agents/docker-container-builder/capabilities/generate-dockerfile/workflow.md +7 -0
  125. package/runtime/agents/docker-container-builder/capabilities/plan-image-build/capability.yaml +18 -0
  126. package/runtime/agents/docker-container-builder/capabilities/plan-image-build/decision-rules.md +6 -0
  127. package/runtime/agents/docker-container-builder/capabilities/plan-image-build/runner.py +32 -0
  128. package/runtime/agents/docker-container-builder/capabilities/plan-image-build/workflow.md +6 -0
  129. package/runtime/agents/docker-container-builder/capabilities/review-docker-security/capability.yaml +21 -0
  130. package/runtime/agents/docker-container-builder/capabilities/review-docker-security/decision-rules.md +6 -0
  131. package/runtime/agents/docker-container-builder/capabilities/review-docker-security/runner.py +43 -0
  132. package/runtime/agents/docker-container-builder/capabilities/review-docker-security/workflow.md +5 -0
  133. package/runtime/agents/docker-container-builder/infra/integrations/docker-container/docker_container_repository.py +837 -0
  134. package/runtime/agents/docker-container-builder/knowledge/context.md +21 -0
  135. package/runtime/agents/docker-container-builder/knowledge/policies.yaml +13 -0
  136. package/runtime/agents/docker-container-builder/knowledge/system.md +21 -0
  137. package/runtime/agents/docker-container-builder/templates/container-plan.md +4 -0
  138. package/runtime/agents/docker-container-builder/templates/container-review.md +4 -0
  139. package/runtime/agents/docker-container-builder/templates/docker-compose.md +5 -0
  140. package/runtime/agents/docker-container-builder/templates/docker-readme.md +3 -0
  141. package/runtime/agents/docker-container-builder/templates/dockerfile.md +5 -0
  142. package/runtime/agents/docker-container-builder/tests/test_runners.py +255 -0
  143. package/runtime/agents/drawio-diagram-builder/agent.yaml +11 -2
  144. package/runtime/agents/drawio-diagram-builder/capabilities/execute-diagram-delivery/capability.yaml +1 -1
  145. package/runtime/agents/drawio-diagram-builder/capabilities/read-azure-card-context/capability.yaml +1 -1
  146. package/runtime/agents/elasticsearch-log-analyzer/agent.yaml +14 -2
  147. package/runtime/agents/elasticsearch-log-analyzer/capabilities/analyze-service-errors/capability.yaml +14 -0
  148. package/runtime/agents/excel-workbook-builder/agent.yaml +10 -0
  149. package/runtime/agents/excel-workbook-builder/capabilities/create-template/capability.yaml +1 -1
  150. package/runtime/agents/excel-workbook-builder/capabilities/create-template/workflow.md +1 -1
  151. package/runtime/agents/excel-workbook-builder/capabilities/create-template-version/capability.yaml +1 -1
  152. package/runtime/agents/excel-workbook-builder/capabilities/generate-template-input-file/capability.yaml +1 -2
  153. package/runtime/agents/excel-workbook-builder/capabilities/refine-template/capability.yaml +1 -1
  154. package/runtime/agents/excel-workbook-builder/capabilities/register-template/capability.yaml +1 -2
  155. package/runtime/agents/excel-workbook-builder/capabilities/register-template/workflow.md +1 -1
  156. package/runtime/agents/execution-loop-builder/AGENTS.md +24 -0
  157. package/runtime/agents/execution-loop-builder/README.md +19 -0
  158. package/runtime/agents/execution-loop-builder/agent.yaml +49 -0
  159. package/runtime/agents/execution-loop-builder/capabilities/generate-loop-project-files/capability.yaml +20 -0
  160. package/runtime/agents/execution-loop-builder/capabilities/generate-loop-project-files/decision-rules.md +6 -0
  161. package/runtime/agents/execution-loop-builder/capabilities/generate-loop-project-files/runner.py +38 -0
  162. package/runtime/agents/execution-loop-builder/capabilities/generate-loop-project-files/workflow.md +7 -0
  163. package/runtime/agents/execution-loop-builder/capabilities/generate-loop-runner/capability.yaml +18 -0
  164. package/runtime/agents/execution-loop-builder/capabilities/generate-loop-runner/decision-rules.md +5 -0
  165. package/runtime/agents/execution-loop-builder/capabilities/generate-loop-runner/runner.py +32 -0
  166. package/runtime/agents/execution-loop-builder/capabilities/generate-loop-runner/workflow.md +6 -0
  167. package/runtime/agents/execution-loop-builder/capabilities/plan-execution-loop/capability.yaml +18 -0
  168. package/runtime/agents/execution-loop-builder/capabilities/plan-execution-loop/decision-rules.md +6 -0
  169. package/runtime/agents/execution-loop-builder/capabilities/plan-execution-loop/runner.py +32 -0
  170. package/runtime/agents/execution-loop-builder/capabilities/plan-execution-loop/workflow.md +6 -0
  171. package/runtime/agents/execution-loop-builder/capabilities/register-loop-task/capability.yaml +19 -0
  172. package/runtime/agents/execution-loop-builder/capabilities/register-loop-task/decision-rules.md +6 -0
  173. package/runtime/agents/execution-loop-builder/capabilities/register-loop-task/runner.py +36 -0
  174. package/runtime/agents/execution-loop-builder/capabilities/register-loop-task/workflow.md +6 -0
  175. package/runtime/agents/execution-loop-builder/capabilities/review-loop-safety/capability.yaml +19 -0
  176. package/runtime/agents/execution-loop-builder/capabilities/review-loop-safety/decision-rules.md +6 -0
  177. package/runtime/agents/execution-loop-builder/capabilities/review-loop-safety/runner.py +39 -0
  178. package/runtime/agents/execution-loop-builder/capabilities/review-loop-safety/workflow.md +5 -0
  179. package/runtime/agents/execution-loop-builder/infra/integrations/execution-loop/execution_loop_repository.py +608 -0
  180. package/runtime/agents/execution-loop-builder/knowledge/context.md +26 -0
  181. package/runtime/agents/execution-loop-builder/knowledge/policies.yaml +13 -0
  182. package/runtime/agents/execution-loop-builder/knowledge/system.md +19 -0
  183. package/runtime/agents/execution-loop-builder/templates/loop-plan.md +3 -0
  184. package/runtime/agents/execution-loop-builder/templates/loop-readme.md +3 -0
  185. package/runtime/agents/execution-loop-builder/templates/loop-review.md +3 -0
  186. package/runtime/agents/execution-loop-builder/templates/loop-runner.py +2 -0
  187. package/runtime/agents/execution-loop-builder/tests/test_runners.py +274 -0
  188. package/runtime/agents/execution-reviewer/agent.yaml +6 -4
  189. package/runtime/agents/execution-reviewer/capabilities/review-agent-result/capability.yaml +1 -2
  190. package/runtime/agents/execution-reviewer/capabilities/review-final-output/capability.yaml +1 -2
  191. package/runtime/agents/execution-reviewer/capabilities/review-plan/capability.yaml +1 -2
  192. package/runtime/agents/figma-ui-ux-product-designer/agent.yaml +17 -5
  193. package/runtime/agents/figma-ui-ux-product-designer/capabilities/analyze-product-context/capability.yaml +1 -1
  194. package/runtime/agents/figma-ui-ux-product-designer/capabilities/conduct-design-interview/capability.yaml +1 -1
  195. package/runtime/agents/figma-ui-ux-product-designer/capabilities/conduct-design-review-session/capability.yaml +1 -1
  196. package/runtime/agents/figma-ui-ux-product-designer/capabilities/generate-dev-handoff/capability.yaml +1 -1
  197. package/runtime/agents/figma-ui-ux-product-designer/capabilities/generate-user-journey-diagram/capability.yaml +1 -1
  198. package/runtime/agents/figma-ui-ux-product-designer/capabilities/ingest-design-source/capability.yaml +1 -1
  199. package/runtime/agents/figma-ui-ux-product-designer/capabilities/triage-design-feedback/capability.yaml +1 -1
  200. package/runtime/agents/generic-agent-builder/AGENTS.md +20 -0
  201. package/runtime/agents/generic-agent-builder/README.md +40 -0
  202. package/runtime/agents/generic-agent-builder/agent.yaml +43 -0
  203. package/runtime/agents/generic-agent-builder/capabilities/generate-agent-instructions/capability.yaml +18 -0
  204. package/runtime/agents/generic-agent-builder/capabilities/generate-agent-instructions/decision-rules.md +5 -0
  205. package/runtime/agents/generic-agent-builder/capabilities/generate-agent-instructions/runner.py +33 -0
  206. package/runtime/agents/generic-agent-builder/capabilities/generate-agent-instructions/workflow.md +6 -0
  207. package/runtime/agents/generic-agent-builder/capabilities/generate-project-agent-files/capability.yaml +20 -0
  208. package/runtime/agents/generic-agent-builder/capabilities/generate-project-agent-files/decision-rules.md +6 -0
  209. package/runtime/agents/generic-agent-builder/capabilities/generate-project-agent-files/runner.py +39 -0
  210. package/runtime/agents/generic-agent-builder/capabilities/generate-project-agent-files/workflow.md +7 -0
  211. package/runtime/agents/generic-agent-builder/capabilities/generate-skill/capability.yaml +18 -0
  212. package/runtime/agents/generic-agent-builder/capabilities/generate-skill/decision-rules.md +5 -0
  213. package/runtime/agents/generic-agent-builder/capabilities/generate-skill/runner.py +33 -0
  214. package/runtime/agents/generic-agent-builder/capabilities/generate-skill/workflow.md +5 -0
  215. package/runtime/agents/generic-agent-builder/capabilities/plan-generic-agent/capability.yaml +18 -0
  216. package/runtime/agents/generic-agent-builder/capabilities/plan-generic-agent/decision-rules.md +6 -0
  217. package/runtime/agents/generic-agent-builder/capabilities/plan-generic-agent/runner.py +33 -0
  218. package/runtime/agents/generic-agent-builder/capabilities/plan-generic-agent/workflow.md +6 -0
  219. package/runtime/agents/generic-agent-builder/capabilities/review-generic-agent/capability.yaml +20 -0
  220. package/runtime/agents/generic-agent-builder/capabilities/review-generic-agent/decision-rules.md +6 -0
  221. package/runtime/agents/generic-agent-builder/capabilities/review-generic-agent/runner.py +40 -0
  222. package/runtime/agents/generic-agent-builder/capabilities/review-generic-agent/workflow.md +7 -0
  223. package/runtime/agents/generic-agent-builder/infra/integrations/generic-agent/generic_agent_repository.py +445 -0
  224. package/runtime/agents/generic-agent-builder/knowledge/context.md +11 -0
  225. package/runtime/agents/generic-agent-builder/knowledge/policies.yaml +12 -0
  226. package/runtime/agents/generic-agent-builder/knowledge/system.md +17 -0
  227. package/runtime/agents/generic-agent-builder/templates/generic-agent-instructions.md +17 -0
  228. package/runtime/agents/generic-agent-builder/templates/generic-review-report.md +13 -0
  229. package/runtime/agents/generic-agent-builder/templates/generic-skill.md +14 -0
  230. package/runtime/agents/generic-agent-builder/tests/test_runners.py +220 -0
  231. package/runtime/agents/github-pr-reviewer/agent.yaml +17 -5
  232. package/runtime/agents/github-pr-reviewer/capabilities/create-review-automation/capability.yaml +1 -1
  233. package/runtime/agents/github-pr-reviewer/capabilities/inspect-pr/capability.yaml +1 -1
  234. package/runtime/agents/github-pr-reviewer/capabilities/list-review-requests/capability.yaml +1 -1
  235. package/runtime/agents/github-pr-reviewer/capabilities/review-pr-diff/capability.yaml +1 -1
  236. package/runtime/agents/knowledge-generator/agent.yaml +13 -3
  237. package/runtime/agents/knowledge-generator/capabilities/generate-knowledge/capability.yaml +1 -1
  238. package/runtime/agents/local-llm-operator/agent.yaml +6 -4
  239. package/runtime/agents/local-llm-operator/capabilities/delegate-operational-task/capability.yaml +1 -2
  240. package/runtime/agents/local-llm-operator/capabilities/inspect-local-models/capability.yaml +1 -2
  241. package/runtime/agents/local-llm-operator/capabilities/select-local-worker/capability.yaml +1 -2
  242. package/runtime/agents/n1-support-agent/agent.yaml +40 -1
  243. package/runtime/agents/n2-support-agent/agent.yaml +41 -2
  244. package/runtime/agents/n2-support-agent/knowledge/policies.yaml +2 -2
  245. package/runtime/agents/notification-operator/AGENTS.md +11 -0
  246. package/runtime/agents/notification-operator/README.md +15 -0
  247. package/runtime/agents/notification-operator/agent.yaml +43 -0
  248. package/runtime/agents/notification-operator/capabilities/configure-notification-channel/capability.yaml +19 -0
  249. package/runtime/agents/notification-operator/capabilities/configure-notification-channel/decision-rules.md +6 -0
  250. package/runtime/agents/notification-operator/capabilities/configure-notification-channel/runner.py +33 -0
  251. package/runtime/agents/notification-operator/capabilities/configure-notification-channel/workflow.md +6 -0
  252. package/runtime/agents/notification-operator/capabilities/format-task-completion-notification/capability.yaml +25 -0
  253. package/runtime/agents/notification-operator/capabilities/format-task-completion-notification/decision-rules.md +7 -0
  254. package/runtime/agents/notification-operator/capabilities/format-task-completion-notification/runner.py +49 -0
  255. package/runtime/agents/notification-operator/capabilities/format-task-completion-notification/workflow.md +6 -0
  256. package/runtime/agents/notification-operator/capabilities/send-task-completion-notification/capability.yaml +27 -0
  257. package/runtime/agents/notification-operator/capabilities/send-task-completion-notification/decision-rules.md +6 -0
  258. package/runtime/agents/notification-operator/capabilities/send-task-completion-notification/runner.py +68 -0
  259. package/runtime/agents/notification-operator/capabilities/send-task-completion-notification/workflow.md +7 -0
  260. package/runtime/agents/notification-operator/infra/README.md +6 -0
  261. package/runtime/agents/notification-operator/knowledge/context.md +10 -0
  262. package/runtime/agents/notification-operator/knowledge/policies.yaml +9 -0
  263. package/runtime/agents/notification-operator/knowledge/system.md +7 -0
  264. package/runtime/agents/notification-operator/templates/README.md +6 -0
  265. package/runtime/agents/notification-operator/tests/test_runners.py +108 -0
  266. package/runtime/agents/playwright-automation-builder/AGENTS.md +23 -0
  267. package/runtime/agents/playwright-automation-builder/README.md +43 -0
  268. package/runtime/agents/playwright-automation-builder/agent.yaml +48 -0
  269. package/runtime/agents/playwright-automation-builder/capabilities/generate-playwright-project-files/capability.yaml +20 -0
  270. package/runtime/agents/playwright-automation-builder/capabilities/generate-playwright-project-files/decision-rules.md +6 -0
  271. package/runtime/agents/playwright-automation-builder/capabilities/generate-playwright-project-files/runner.py +38 -0
  272. package/runtime/agents/playwright-automation-builder/capabilities/generate-playwright-project-files/workflow.md +6 -0
  273. package/runtime/agents/playwright-automation-builder/capabilities/generate-playwright-script/capability.yaml +18 -0
  274. package/runtime/agents/playwright-automation-builder/capabilities/generate-playwright-script/decision-rules.md +6 -0
  275. package/runtime/agents/playwright-automation-builder/capabilities/generate-playwright-script/runner.py +32 -0
  276. package/runtime/agents/playwright-automation-builder/capabilities/generate-playwright-script/workflow.md +6 -0
  277. package/runtime/agents/playwright-automation-builder/capabilities/plan-playwright-automation/capability.yaml +18 -0
  278. package/runtime/agents/playwright-automation-builder/capabilities/plan-playwright-automation/decision-rules.md +6 -0
  279. package/runtime/agents/playwright-automation-builder/capabilities/plan-playwright-automation/runner.py +32 -0
  280. package/runtime/agents/playwright-automation-builder/capabilities/plan-playwright-automation/workflow.md +6 -0
  281. package/runtime/agents/playwright-automation-builder/capabilities/review-playwright-artifacts/capability.yaml +19 -0
  282. package/runtime/agents/playwright-automation-builder/capabilities/review-playwright-artifacts/decision-rules.md +6 -0
  283. package/runtime/agents/playwright-automation-builder/capabilities/review-playwright-artifacts/runner.py +33 -0
  284. package/runtime/agents/playwright-automation-builder/capabilities/review-playwright-artifacts/workflow.md +6 -0
  285. package/runtime/agents/playwright-automation-builder/capabilities/run-playwright-check/capability.yaml +22 -0
  286. package/runtime/agents/playwright-automation-builder/capabilities/run-playwright-check/decision-rules.md +6 -0
  287. package/runtime/agents/playwright-automation-builder/capabilities/run-playwright-check/runner.py +40 -0
  288. package/runtime/agents/playwright-automation-builder/capabilities/run-playwright-check/workflow.md +6 -0
  289. package/runtime/agents/playwright-automation-builder/capabilities/wrap-playwright-as-capability/capability.yaml +22 -0
  290. package/runtime/agents/playwright-automation-builder/capabilities/wrap-playwright-as-capability/decision-rules.md +6 -0
  291. package/runtime/agents/playwright-automation-builder/capabilities/wrap-playwright-as-capability/runner.py +42 -0
  292. package/runtime/agents/playwright-automation-builder/capabilities/wrap-playwright-as-capability/workflow.md +6 -0
  293. package/runtime/agents/playwright-automation-builder/infra/integrations/playwright-automation/playwright_automation_repository.py +865 -0
  294. package/runtime/agents/playwright-automation-builder/knowledge/context.md +19 -0
  295. package/runtime/agents/playwright-automation-builder/knowledge/policies.yaml +25 -0
  296. package/runtime/agents/playwright-automation-builder/knowledge/system.md +19 -0
  297. package/runtime/agents/playwright-automation-builder/templates/capability-wrapper.md +4 -0
  298. package/runtime/agents/playwright-automation-builder/templates/playwright-automation.py +12 -0
  299. package/runtime/agents/playwright-automation-builder/templates/playwright-readme.md +13 -0
  300. package/runtime/agents/playwright-automation-builder/templates/playwright-review-report.md +9 -0
  301. package/runtime/agents/playwright-automation-builder/templates/playwright-test.py +2 -0
  302. package/runtime/agents/playwright-automation-builder/tests/test_runners.py +261 -0
  303. package/runtime/agents/postgres-data-analyzer/agent.yaml +13 -2
  304. package/runtime/agents/presentation-deck-builder/agent.yaml +14 -3
  305. package/runtime/agents/presentation-deck-builder/capabilities/create-template/capability.yaml +1 -1
  306. package/runtime/agents/presentation-deck-builder/capabilities/create-template-version/capability.yaml +1 -1
  307. package/runtime/agents/presentation-deck-builder/capabilities/generate-template-input-file/capability.yaml +1 -1
  308. package/runtime/agents/presentation-deck-builder/capabilities/refine-template/capability.yaml +1 -1
  309. package/runtime/agents/presentation-deck-builder/capabilities/register-template/capability.yaml +1 -1
  310. package/runtime/agents/presentation-deck-builder/knowledge/prompts/create-template.md +1 -1
  311. package/runtime/agents/presentation-deck-builder/knowledge/prompts/generate-template-input-file.md +1 -1
  312. package/runtime/agents/provider-configurator/agent.yaml +6 -4
  313. package/runtime/agents/provider-configurator/capabilities/collect-provider-credentials/capability.yaml +1 -2
  314. package/runtime/agents/provider-configurator/capabilities/configure-provider-source/capability.yaml +1 -2
  315. package/runtime/agents/provider-configurator/capabilities/validate-provider-readiness/capability.yaml +1 -2
  316. package/runtime/agents/pyautogui-automation-builder/AGENTS.md +32 -0
  317. package/runtime/agents/pyautogui-automation-builder/README.md +44 -0
  318. package/runtime/agents/pyautogui-automation-builder/agent.yaml +45 -0
  319. package/runtime/agents/pyautogui-automation-builder/capabilities/generate-pyautogui-project-files/capability.yaml +20 -0
  320. package/runtime/agents/pyautogui-automation-builder/capabilities/generate-pyautogui-project-files/decision-rules.md +6 -0
  321. package/runtime/agents/pyautogui-automation-builder/capabilities/generate-pyautogui-project-files/runner.py +39 -0
  322. package/runtime/agents/pyautogui-automation-builder/capabilities/generate-pyautogui-project-files/workflow.md +7 -0
  323. package/runtime/agents/pyautogui-automation-builder/capabilities/generate-pyautogui-script/capability.yaml +18 -0
  324. package/runtime/agents/pyautogui-automation-builder/capabilities/generate-pyautogui-script/decision-rules.md +7 -0
  325. package/runtime/agents/pyautogui-automation-builder/capabilities/generate-pyautogui-script/runner.py +33 -0
  326. package/runtime/agents/pyautogui-automation-builder/capabilities/generate-pyautogui-script/workflow.md +7 -0
  327. package/runtime/agents/pyautogui-automation-builder/capabilities/plan-desktop-automation/capability.yaml +18 -0
  328. package/runtime/agents/pyautogui-automation-builder/capabilities/plan-desktop-automation/decision-rules.md +8 -0
  329. package/runtime/agents/pyautogui-automation-builder/capabilities/plan-desktop-automation/runner.py +33 -0
  330. package/runtime/agents/pyautogui-automation-builder/capabilities/plan-desktop-automation/workflow.md +9 -0
  331. package/runtime/agents/pyautogui-automation-builder/capabilities/review-pyautogui-script/capability.yaml +20 -0
  332. package/runtime/agents/pyautogui-automation-builder/capabilities/review-pyautogui-script/decision-rules.md +8 -0
  333. package/runtime/agents/pyautogui-automation-builder/capabilities/review-pyautogui-script/runner.py +43 -0
  334. package/runtime/agents/pyautogui-automation-builder/capabilities/review-pyautogui-script/workflow.md +7 -0
  335. package/runtime/agents/pyautogui-automation-builder/capabilities/wrap-pyautogui-as-capability/capability.yaml +22 -0
  336. package/runtime/agents/pyautogui-automation-builder/capabilities/wrap-pyautogui-as-capability/decision-rules.md +6 -0
  337. package/runtime/agents/pyautogui-automation-builder/capabilities/wrap-pyautogui-as-capability/runner.py +43 -0
  338. package/runtime/agents/pyautogui-automation-builder/capabilities/wrap-pyautogui-as-capability/workflow.md +7 -0
  339. package/runtime/agents/pyautogui-automation-builder/infra/integrations/pyautogui-automation/pyautogui_automation_repository.py +856 -0
  340. package/runtime/agents/pyautogui-automation-builder/knowledge/context.md +17 -0
  341. package/runtime/agents/pyautogui-automation-builder/knowledge/policies.yaml +24 -0
  342. package/runtime/agents/pyautogui-automation-builder/knowledge/system.md +13 -0
  343. package/runtime/agents/pyautogui-automation-builder/templates/capability-wrapper.md +3 -0
  344. package/runtime/agents/pyautogui-automation-builder/templates/pyautogui-automation.py +12 -0
  345. package/runtime/agents/pyautogui-automation-builder/templates/pyautogui-readme.md +3 -0
  346. package/runtime/agents/pyautogui-automation-builder/templates/pyautogui-review-report.md +3 -0
  347. package/runtime/agents/pyautogui-automation-builder/templates/pyautogui-test.py +2 -0
  348. package/runtime/agents/pyautogui-automation-builder/tests/test_runners.py +376 -0
  349. package/runtime/agents/python-automation-builder/AGENTS.md +25 -0
  350. package/runtime/agents/python-automation-builder/README.md +43 -0
  351. package/runtime/agents/python-automation-builder/agent.yaml +45 -0
  352. package/runtime/agents/python-automation-builder/capabilities/generate-automation-project-files/capability.yaml +20 -0
  353. package/runtime/agents/python-automation-builder/capabilities/generate-automation-project-files/decision-rules.md +6 -0
  354. package/runtime/agents/python-automation-builder/capabilities/generate-automation-project-files/runner.py +39 -0
  355. package/runtime/agents/python-automation-builder/capabilities/generate-automation-project-files/workflow.md +7 -0
  356. package/runtime/agents/python-automation-builder/capabilities/generate-python-automation/capability.yaml +18 -0
  357. package/runtime/agents/python-automation-builder/capabilities/generate-python-automation/decision-rules.md +5 -0
  358. package/runtime/agents/python-automation-builder/capabilities/generate-python-automation/runner.py +33 -0
  359. package/runtime/agents/python-automation-builder/capabilities/generate-python-automation/workflow.md +5 -0
  360. package/runtime/agents/python-automation-builder/capabilities/plan-python-automation/capability.yaml +18 -0
  361. package/runtime/agents/python-automation-builder/capabilities/plan-python-automation/decision-rules.md +6 -0
  362. package/runtime/agents/python-automation-builder/capabilities/plan-python-automation/runner.py +33 -0
  363. package/runtime/agents/python-automation-builder/capabilities/plan-python-automation/workflow.md +6 -0
  364. package/runtime/agents/python-automation-builder/capabilities/review-python-automation/capability.yaml +20 -0
  365. package/runtime/agents/python-automation-builder/capabilities/review-python-automation/decision-rules.md +6 -0
  366. package/runtime/agents/python-automation-builder/capabilities/review-python-automation/runner.py +43 -0
  367. package/runtime/agents/python-automation-builder/capabilities/review-python-automation/workflow.md +5 -0
  368. package/runtime/agents/python-automation-builder/capabilities/wrap-automation-as-capability/capability.yaml +22 -0
  369. package/runtime/agents/python-automation-builder/capabilities/wrap-automation-as-capability/decision-rules.md +6 -0
  370. package/runtime/agents/python-automation-builder/capabilities/wrap-automation-as-capability/runner.py +43 -0
  371. package/runtime/agents/python-automation-builder/capabilities/wrap-automation-as-capability/workflow.md +6 -0
  372. package/runtime/agents/python-automation-builder/infra/integrations/python-automation/python_automation_repository.py +717 -0
  373. package/runtime/agents/python-automation-builder/knowledge/context.md +15 -0
  374. package/runtime/agents/python-automation-builder/knowledge/policies.yaml +12 -0
  375. package/runtime/agents/python-automation-builder/knowledge/system.md +19 -0
  376. package/runtime/agents/python-automation-builder/templates/automation-readme.md +13 -0
  377. package/runtime/agents/python-automation-builder/templates/automation-review-report.md +13 -0
  378. package/runtime/agents/python-automation-builder/templates/automation-test.py +9 -0
  379. package/runtime/agents/python-automation-builder/templates/automation.py +19 -0
  380. package/runtime/agents/python-automation-builder/templates/capability-wrapper.md +4 -0
  381. package/runtime/agents/python-automation-builder/tests/test_runners.py +292 -0
  382. package/runtime/agents/selenium-automation-builder/AGENTS.md +27 -0
  383. package/runtime/agents/selenium-automation-builder/README.md +40 -0
  384. package/runtime/agents/selenium-automation-builder/agent.yaml +45 -0
  385. package/runtime/agents/selenium-automation-builder/capabilities/generate-selenium-project-files/capability.yaml +20 -0
  386. package/runtime/agents/selenium-automation-builder/capabilities/generate-selenium-project-files/decision-rules.md +6 -0
  387. package/runtime/agents/selenium-automation-builder/capabilities/generate-selenium-project-files/runner.py +39 -0
  388. package/runtime/agents/selenium-automation-builder/capabilities/generate-selenium-project-files/workflow.md +7 -0
  389. package/runtime/agents/selenium-automation-builder/capabilities/generate-selenium-script/capability.yaml +18 -0
  390. package/runtime/agents/selenium-automation-builder/capabilities/generate-selenium-script/decision-rules.md +6 -0
  391. package/runtime/agents/selenium-automation-builder/capabilities/generate-selenium-script/runner.py +33 -0
  392. package/runtime/agents/selenium-automation-builder/capabilities/generate-selenium-script/workflow.md +6 -0
  393. package/runtime/agents/selenium-automation-builder/capabilities/plan-selenium-automation/capability.yaml +18 -0
  394. package/runtime/agents/selenium-automation-builder/capabilities/plan-selenium-automation/decision-rules.md +6 -0
  395. package/runtime/agents/selenium-automation-builder/capabilities/plan-selenium-automation/runner.py +33 -0
  396. package/runtime/agents/selenium-automation-builder/capabilities/plan-selenium-automation/workflow.md +6 -0
  397. package/runtime/agents/selenium-automation-builder/capabilities/review-selenium-script/capability.yaml +20 -0
  398. package/runtime/agents/selenium-automation-builder/capabilities/review-selenium-script/decision-rules.md +6 -0
  399. package/runtime/agents/selenium-automation-builder/capabilities/review-selenium-script/runner.py +40 -0
  400. package/runtime/agents/selenium-automation-builder/capabilities/review-selenium-script/workflow.md +6 -0
  401. package/runtime/agents/selenium-automation-builder/capabilities/wrap-selenium-as-capability/capability.yaml +22 -0
  402. package/runtime/agents/selenium-automation-builder/capabilities/wrap-selenium-as-capability/decision-rules.md +6 -0
  403. package/runtime/agents/selenium-automation-builder/capabilities/wrap-selenium-as-capability/runner.py +43 -0
  404. package/runtime/agents/selenium-automation-builder/capabilities/wrap-selenium-as-capability/workflow.md +6 -0
  405. package/runtime/agents/selenium-automation-builder/infra/integrations/selenium-automation/selenium_automation_repository.py +793 -0
  406. package/runtime/agents/selenium-automation-builder/knowledge/context.md +15 -0
  407. package/runtime/agents/selenium-automation-builder/knowledge/policies.yaml +17 -0
  408. package/runtime/agents/selenium-automation-builder/knowledge/system.md +18 -0
  409. package/runtime/agents/selenium-automation-builder/templates/capability-wrapper.md +4 -0
  410. package/runtime/agents/selenium-automation-builder/templates/selenium-automation.py +20 -0
  411. package/runtime/agents/selenium-automation-builder/templates/selenium-readme.md +13 -0
  412. package/runtime/agents/selenium-automation-builder/templates/selenium-review-report.md +13 -0
  413. package/runtime/agents/selenium-automation-builder/templates/selenium-test.py +9 -0
  414. package/runtime/agents/selenium-automation-builder/tests/test_runners.py +282 -0
  415. package/runtime/agents/software-specification-analyst/agent.yaml +17 -4
  416. package/runtime/agents/software-specification-analyst/capabilities/analyze-multiple-projects/capability.yaml +1 -1
  417. package/runtime/agents/software-specification-analyst/capabilities/analyze-project-context/capability.yaml +1 -1
  418. package/runtime/agents/software-specification-analyst/capabilities/conduct-requirements-interview/capability.yaml +1 -1
  419. package/runtime/agents/software-specification-analyst/capabilities/create-complete-spec/capability.yaml +1 -1
  420. package/runtime/agents/software-specification-analyst/capabilities/create-final-spec-from-analysis/capability.yaml +1 -1
  421. package/runtime/agents/software-specification-analyst/capabilities/create-functional-spec/capability.yaml +11 -0
  422. package/runtime/agents/software-specification-analyst/capabilities/create-technical-spec/capability.yaml +12 -0
  423. package/runtime/agents/software-specification-analyst/capabilities/refine-analysis-with-feedback/capability.yaml +1 -1
  424. package/runtime/agents/software-specification-analyst/capabilities/write-user-stories/capability.yaml +12 -0
  425. package/runtime/agents/sqlserver-change-operator/agent.yaml +12 -1
  426. package/runtime/agents/sqlserver-data-analyzer/agent.yaml +13 -2
  427. package/runtime/agents/supabase-project-analyst/AGENTS.md +29 -0
  428. package/runtime/agents/supabase-project-analyst/README.md +23 -0
  429. package/runtime/agents/supabase-project-analyst/agent.yaml +53 -0
  430. package/runtime/agents/supabase-project-analyst/capabilities/audit-auth-security/capability.yaml +18 -0
  431. package/runtime/agents/supabase-project-analyst/capabilities/audit-auth-security/decision-rules.md +5 -0
  432. package/runtime/agents/supabase-project-analyst/capabilities/audit-auth-security/runner.py +32 -0
  433. package/runtime/agents/supabase-project-analyst/capabilities/audit-auth-security/workflow.md +6 -0
  434. package/runtime/agents/supabase-project-analyst/capabilities/audit-rls-policies/capability.yaml +18 -0
  435. package/runtime/agents/supabase-project-analyst/capabilities/audit-rls-policies/decision-rules.md +6 -0
  436. package/runtime/agents/supabase-project-analyst/capabilities/audit-rls-policies/runner.py +32 -0
  437. package/runtime/agents/supabase-project-analyst/capabilities/audit-rls-policies/workflow.md +7 -0
  438. package/runtime/agents/supabase-project-analyst/capabilities/audit-storage-policies/capability.yaml +18 -0
  439. package/runtime/agents/supabase-project-analyst/capabilities/audit-storage-policies/decision-rules.md +5 -0
  440. package/runtime/agents/supabase-project-analyst/capabilities/audit-storage-policies/runner.py +32 -0
  441. package/runtime/agents/supabase-project-analyst/capabilities/audit-storage-policies/workflow.md +6 -0
  442. package/runtime/agents/supabase-project-analyst/capabilities/generate-supabase-report/capability.yaml +18 -0
  443. package/runtime/agents/supabase-project-analyst/capabilities/generate-supabase-report/decision-rules.md +6 -0
  444. package/runtime/agents/supabase-project-analyst/capabilities/generate-supabase-report/runner.py +32 -0
  445. package/runtime/agents/supabase-project-analyst/capabilities/generate-supabase-report/workflow.md +6 -0
  446. package/runtime/agents/supabase-project-analyst/capabilities/inspect-supabase-project/capability.yaml +19 -0
  447. package/runtime/agents/supabase-project-analyst/capabilities/inspect-supabase-project/decision-rules.md +6 -0
  448. package/runtime/agents/supabase-project-analyst/capabilities/inspect-supabase-project/runner.py +36 -0
  449. package/runtime/agents/supabase-project-analyst/capabilities/inspect-supabase-project/workflow.md +7 -0
  450. package/runtime/agents/supabase-project-analyst/capabilities/plan-supabase-fix/capability.yaml +18 -0
  451. package/runtime/agents/supabase-project-analyst/capabilities/plan-supabase-fix/decision-rules.md +6 -0
  452. package/runtime/agents/supabase-project-analyst/capabilities/plan-supabase-fix/runner.py +32 -0
  453. package/runtime/agents/supabase-project-analyst/capabilities/plan-supabase-fix/workflow.md +6 -0
  454. package/runtime/agents/supabase-project-analyst/capabilities/review-migrations/capability.yaml +18 -0
  455. package/runtime/agents/supabase-project-analyst/capabilities/review-migrations/decision-rules.md +6 -0
  456. package/runtime/agents/supabase-project-analyst/capabilities/review-migrations/runner.py +32 -0
  457. package/runtime/agents/supabase-project-analyst/capabilities/review-migrations/workflow.md +5 -0
  458. package/runtime/agents/supabase-project-analyst/infra/integrations/supabase-project/supabase_project_repository.py +589 -0
  459. package/runtime/agents/supabase-project-analyst/knowledge/context.md +11 -0
  460. package/runtime/agents/supabase-project-analyst/knowledge/policies.yaml +24 -0
  461. package/runtime/agents/supabase-project-analyst/knowledge/system.md +10 -0
  462. package/runtime/agents/supabase-project-analyst/templates/supabase-audit.md +3 -0
  463. package/runtime/agents/supabase-project-analyst/templates/supabase-fix-plan.md +3 -0
  464. package/runtime/agents/supabase-project-analyst/templates/supabase-inspection.md +3 -0
  465. package/runtime/agents/supabase-project-analyst/templates/supabase-report.md +3 -0
  466. package/runtime/agents/supabase-project-analyst/tests/test_runners.py +239 -0
  467. package/runtime/agents/task-orchestrator/agent.yaml +25 -3
  468. package/runtime/agents/task-orchestrator/capabilities/plan-task/capability.yaml +1 -2
  469. package/runtime/agents/task-orchestrator/capabilities/select-specialists/capability.yaml +1 -2
  470. package/runtime/agents/technical-integration-analyst/agent.yaml +15 -2
  471. package/runtime/agents/topdesk-orchestrator/agent.yaml +10 -2
  472. package/runtime/cli/aikit/__init__.py +1 -1
  473. package/runtime/cli/aikit/acceptance.py +166 -0
  474. package/runtime/cli/aikit/agent_executor.py +26 -3
  475. package/runtime/cli/aikit/agent_registry.py +244 -5
  476. package/runtime/cli/aikit/architecture.py +84 -0
  477. package/runtime/cli/aikit/audit.py +172 -3
  478. package/runtime/cli/aikit/autonomy.py +237 -0
  479. package/runtime/cli/aikit/capability_runtime.py +522 -0
  480. package/runtime/cli/aikit/catalog.py +246 -0
  481. package/runtime/cli/aikit/cli_dispatch.py +1078 -0
  482. package/runtime/cli/aikit/cli_parser.py +409 -0
  483. package/runtime/cli/aikit/collaboration.py +359 -0
  484. package/runtime/cli/aikit/configuration_orchestrator.py +52 -26
  485. package/runtime/cli/aikit/contribution.py +105 -0
  486. package/runtime/cli/aikit/core/__init__.py +1 -0
  487. package/runtime/cli/aikit/core/capability_contract.py +112 -0
  488. package/runtime/cli/aikit/core/requests.py +69 -0
  489. package/runtime/cli/aikit/core/runtime.py +64 -0
  490. package/runtime/cli/aikit/diagnostics.py +8 -2
  491. package/runtime/cli/aikit/doctor_runtime.py +79 -0
  492. package/runtime/cli/aikit/errors.py +7 -0
  493. package/runtime/cli/aikit/eval.py +158 -0
  494. package/runtime/cli/aikit/execution_reviewer.py +21 -0
  495. package/runtime/cli/aikit/extensions.py +140 -0
  496. package/runtime/cli/aikit/fallback.py +1 -0
  497. package/runtime/cli/aikit/github_pr.py +23 -0
  498. package/runtime/cli/aikit/guardrails.py +25 -10
  499. package/runtime/cli/aikit/human_output.py +1026 -0
  500. package/runtime/cli/aikit/impact_map.py +294 -0
  501. package/runtime/cli/aikit/interactive_wizard.py +79 -0
  502. package/runtime/cli/aikit/local_llm_operator.py +35 -1
  503. package/runtime/cli/aikit/main.py +9 -2834
  504. package/runtime/cli/aikit/mcp_manifest.py +229 -0
  505. package/runtime/cli/aikit/mcp_server.py +132 -0
  506. package/runtime/cli/aikit/mcp_tools.py +262 -0
  507. package/runtime/cli/aikit/mini_brain.py +227 -0
  508. package/runtime/cli/aikit/model_router.py +182 -18
  509. package/runtime/cli/aikit/module_controller.py +335 -0
  510. package/runtime/cli/aikit/natural_prompt_runtime.py +538 -0
  511. package/runtime/cli/aikit/notifications.py +716 -2
  512. package/runtime/cli/aikit/ollama.py +1 -0
  513. package/runtime/cli/aikit/orchestrator.py +809 -119
  514. package/runtime/cli/aikit/output.py +63 -2
  515. package/runtime/cli/aikit/permissions.py +14 -4
  516. package/runtime/cli/aikit/prompt_injection.py +57 -0
  517. package/runtime/cli/aikit/review_gate.py +38 -6
  518. package/runtime/cli/aikit/roadmap.py +195 -0
  519. package/runtime/cli/aikit/roadmap_cli.py +70 -0
  520. package/runtime/cli/aikit/router.py +41 -12
  521. package/runtime/cli/aikit/router_explain.py +152 -0
  522. package/runtime/cli/aikit/runtime_paths.py +11 -0
  523. package/runtime/cli/aikit/secrets.py +113 -0
  524. package/runtime/cli/aikit/sessions.py +88 -2
  525. package/runtime/cli/aikit/setup_wizard_payload.py +32 -0
  526. package/runtime/cli/aikit/sources.py +298 -50
  527. package/runtime/cli/aikit/tasks.py +449 -21
  528. package/runtime/cli/aikit/wizard_state.py +15 -1
  529. package/runtime/cli/aikit/workflows.py +115 -0
  530. package/runtime/cli/aikit/write_policy.py +108 -0
  531. package/runtime/plugins/claude-code-ai-devkit/README.md +17 -0
  532. package/runtime/plugins/claude-code-ai-devkit/agents/README.md +29 -2
  533. package/runtime/plugins/claude-code-ai-devkit/agents/agent-devkit-db-analyst.md +44 -0
  534. package/runtime/plugins/claude-code-ai-devkit/agents/agent-devkit-execution-reviewer.md +38 -0
  535. package/runtime/plugins/claude-code-ai-devkit/agents/agent-devkit-pr-reviewer.md +42 -0
  536. package/runtime/plugins/claude-code-ai-devkit/agents/agent-devkit-repo-explorer.md +40 -0
  537. package/runtime/plugins/claude-code-ai-devkit/agents/agent-devkit-support-triage.md +43 -0
  538. package/runtime/plugins/claude-code-ai-devkit/plugin.json +1 -1
  539. package/runtime/plugins/claude-code-ai-devkit/skills/ai-devkit-router/SKILL.md +16 -0
  540. package/runtime/plugins/claude-skill-ai-devkit/ai-devkit/SKILL.md +1 -0
  541. package/runtime/plugins/claude-skill-ai-devkit/ai-devkit/references/subagents.md +21 -0
  542. package/runtime/plugins/claude-skill-ai-devkit/plugin.json +1 -1
  543. package/runtime/providers/azure-devops.yaml +9 -0
  544. package/runtime/providers/github.yaml +4 -0
  545. package/runtime/providers/local-notification.yaml +5 -2
  546. package/runtime/providers/local-scheduler.yaml +1 -1
  547. package/runtime/providers/supabase.yaml +46 -0
  548. package/runtime/scripts/release-catalog-snapshot.json +543 -0
  549. package/runtime/scripts/release-gate.py +141 -1
  550. package/runtime/scripts/validate-repo.py +312 -0
  551. package/runtime/vendor/skills/napkin/napkin.md +15 -9
@@ -1,154 +1,16 @@
1
1
  #!/usr/bin/env python3
2
- """AI DevKit public command line interface."""
2
+ """AI DevKit public command line entrypoint."""
3
3
 
4
4
  from __future__ import annotations
5
5
 
6
- import argparse
7
6
  import json
8
- import os
9
- import shutil
10
- import subprocess
11
7
  import sys
12
- from pathlib import Path
13
- from typing import Any
14
8
 
15
- from cli.aikit.aliases import add_alias, list_aliases, remove_alias, sync_aliases
16
- from cli.aikit import __version__
17
- from cli.aikit.agent_executor import execute_plan_tasks
18
- from cli.aikit.app_home import app_home_status, migrate_default_home
19
- from cli.aikit.audit import export_audit, list_audits, record_audit, show_audit
20
- from cli.aikit.calendar import calendar_list, calendar_summary, calendar_today, calendar_tomorrow, configure_calendar
21
- from cli.aikit.configuration_orchestrator import provider_wizard_from_requirement
22
- from cli.aikit.control_router import dispatch_natural_control_prompt as route_natural_control_prompt
23
- from cli.aikit.control_router import plan_natural_control_prompt
24
- from cli.aikit.decision_store import forget_decision, list_decisions, reset_decisions, set_decision
25
- from cli.aikit.diagnostics import build_diagnostics
26
- from cli.aikit.execution_reviewer import enforce_execution_review
27
- from cli.aikit.fallback import evaluate_provider_requirements
28
- from cli.aikit.github_pr import pr_create_automation, pr_inspect, pr_list_review_requests, pr_review
29
- from cli.aikit.guardrails import evaluate_execution_guardrails
30
- from cli.aikit.identity import enforce_identity_response, is_identity_question, local_identity_response, public_name
31
- from cli.aikit.llm import (
32
- configure_backend,
33
- doctor_backends,
34
- invoke_agent_prompt,
35
- list_backends,
36
- llm_preference,
37
- set_default_backend,
38
- set_llm_preference,
39
- )
40
- from cli.aikit.memory import memory_path_payload, napkin_context, record_usage, reset_memory, show_memory
41
- from cli.aikit.model_router import build_model_plan
42
- from cli.aikit.ollama import ollama_models, ollama_pull, ollama_status, ollama_update
43
- from cli.aikit.local_llm_operator import enrich_prompt_with_local_result, maybe_delegate_local_llm
44
- from cli.aikit.orchestrator import (
45
- attach_source_to_primary_task,
46
- build_execution_plan,
47
- mark_plan_after_execution,
48
- mark_review_task,
49
- )
50
- from cli.aikit.personality import load_personality, reset_personality, setup_personality, update_personality
51
- from cli.aikit.permissions import grant_permission, revoke_permission, show_permissions
52
- from cli.aikit.provider_wizard import missing_source_wizard
53
- from cli.aikit.review_gate import build_review_gate
54
- from cli.aikit.sessions import (
55
- build_contextual_prompt,
56
- get_or_create_session,
57
- list_sessions,
58
- record_exchange,
59
- resume_session,
60
- show_session,
61
- )
62
- from cli.aikit.setup_wizard import setup_wizard
63
- from cli.aikit.scheduler import run_scheduler_once, scheduler_daemon_plan
64
- from cli.aikit.tasks import (
65
- create_task,
66
- delete_task,
67
- list_tasks,
68
- run_task,
69
- show_task,
70
- task_history,
71
- update_task_schedule,
72
- update_task_status,
73
- )
74
- from cli.aikit.toolchain import doctor_toolchain, install_toolchain, list_toolchain
75
- from cli.aikit.install import InstallError, install_runtime
76
- from cli.aikit.lock import lock_status, parse_profiles
77
- from cli.aikit.output import run_payload
78
- from cli.aikit.credentials import CredentialResolverError, credential_backends
79
- from cli.aikit.providers import (
80
- ProviderRegistryError,
81
- configure_provider,
82
- credential_resolution,
83
- list_providers,
84
- provider_status_with_credentials,
85
- unset_provider_config,
86
- )
87
- from cli.aikit.router import route_prompt
88
- from cli.aikit.sources import (
89
- SourceRegistryError,
90
- add_source,
91
- apply_source_to_args,
92
- extract_source_arg,
93
- list_sources,
94
- public_source,
95
- remove_source,
96
- resolve_source,
97
- source_env,
98
- source_status,
99
- )
100
- from cli.aikit.wizard_state import (
101
- WizardStateError,
102
- answer_wizard,
103
- cancel_wizard,
104
- create_provider_wizard,
105
- list_wizards,
106
- show_wizard,
107
- )
108
-
109
-
110
- DEFAULT_ROOT = Path(__file__).resolve().parents[2]
111
- ROOT = Path(os.environ.get("AI_DEVKIT_ROOT", DEFAULT_ROOT)).resolve()
112
- AGENTS_DIR = ROOT / "agents"
113
-
114
- DETERMINISTIC_COMMANDS = (
115
- "agents",
116
- "capabilities",
117
- "inspect",
118
- "run",
119
- "doctor",
120
- "commands",
121
- "llm",
122
- "providers",
123
- "provider",
124
- "credential",
125
- "source",
126
- "memory",
127
- "personality",
128
- "setup",
129
- "alias",
130
- "session",
131
- "toolchain",
132
- "task",
133
- "scheduler",
134
- "calendar",
135
- "pr",
136
- "permissions",
137
- "audit",
138
- "config",
139
- "tools",
140
- "integrations",
141
- "skills",
142
- "decisions",
143
- "ollama",
144
- "install",
145
- "wizard",
146
- )
147
- LLM_COMMANDS = ("agent",)
148
-
149
-
150
- class DevKitError(RuntimeError):
151
- """Raised for user-facing CLI errors."""
9
+ from cli.aikit.cli_dispatch import dispatch, format_audit_warning, is_audit_warning, maybe_record_cli_audit
10
+ from cli.aikit.cli_parser import DETERMINISTIC_COMMANDS, LLM_COMMANDS, build_parser
11
+ from cli.aikit.errors import DevKitError
12
+ from cli.aikit.human_output import print_human
13
+ from cli.aikit.interactive_wizard import maybe_run_interactive_wizard
152
14
 
153
15
 
154
16
  def main(argv: list[str] | None = None, *, prog: str | None = None) -> int:
@@ -159,7 +21,9 @@ def main(argv: list[str] | None = None, *, prog: str | None = None) -> int:
159
21
  try:
160
22
  result = dispatch(args)
161
23
  except DevKitError as exc:
162
- maybe_record_cli_audit(args, result=None, error=str(exc))
24
+ audit_result = maybe_record_cli_audit(args, result=None, error=str(exc))
25
+ if is_audit_warning(audit_result):
26
+ print(format_audit_warning(audit_result), file=sys.stderr)
163
27
  print(f"error: {exc}", file=sys.stderr)
164
28
  return 1
165
29
 
@@ -180,2694 +44,5 @@ def main(argv: list[str] | None = None, *, prog: str | None = None) -> int:
180
44
  return 0
181
45
 
182
46
 
183
- def build_parser(prog: str | None = None) -> argparse.ArgumentParser:
184
- parser = argparse.ArgumentParser(
185
- prog=prog or "aikit",
186
- description="AI DevKit CLI",
187
- )
188
- parser.add_argument("--json", action="store_true", help="print machine-readable JSON")
189
- parser.add_argument("--dry-run", dest="global_dry_run", action="store_true", help="show execution plan without external write effects")
190
- parser.add_argument("-v", "--version", action="store_true", help="print CLI version and exit")
191
- parser.add_argument(
192
- "-s",
193
- "--sessions",
194
- dest="sessions_shortcut",
195
- action="store_true",
196
- help="list local conversation sessions and exit",
197
- )
198
-
199
- subparsers = parser.add_subparsers(dest="command")
200
-
201
- agent_parser = subparsers.add_parser(
202
- "agent",
203
- help="handle a natural-language task using an LLM backend",
204
- )
205
- agent_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
206
- agent_parser.add_argument("--llm", help="LLM backend id to use")
207
- agent_parser.add_argument("--dry-run", action="store_true", help="show execution plan without invoking LLM or external writes")
208
- agent_parser.add_argument("--no-llm-fallback", action="store_true", help="disable automatic fallback to secondary LLM backends")
209
- agent_parser.add_argument("--session", dest="session_id", help="resume a local conversation session")
210
- agent_parser.add_argument("--new-session", action="store_true", help="start a new local conversation session")
211
- agent_parser.add_argument("prompt", nargs=argparse.REMAINDER)
212
-
213
- commands_parser = subparsers.add_parser("commands", help="list CLI command modes")
214
- commands_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
215
- commands_parser.add_argument("action", nargs="?", default="list", choices=["list"])
216
-
217
- providers_parser = subparsers.add_parser("providers", help="list provider registry entries")
218
- providers_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
219
- providers_parser.add_argument("action", nargs="?", default="list", choices=["list"])
220
-
221
- provider_parser = subparsers.add_parser("provider", help="inspect or configure one provider")
222
- provider_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
223
- provider_parser.add_argument("--env-file", action="append", default=[], help="credential env/JSON/YAML file to inspect without printing values")
224
- provider_parser.add_argument("--env", action="append", default=[], help="persist an environment variable reference for provider configuration")
225
- provider_parser.add_argument("--from-env", action="store_true", help="persist references for provider fields found in the current environment")
226
- provider_parser.add_argument("--session-only", action="store_true", help="validate configuration for this invocation without writing config")
227
- provider_parser.add_argument("action", nargs="?", default="status", choices=["status", "doctor", "configure", "unset"])
228
- provider_parser.add_argument("provider", nargs="?")
229
-
230
- credential_parser = subparsers.add_parser("credential", help="resolve provider credentials without exposing values")
231
- credential_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
232
- credential_parser.add_argument("--env-file", action="append", default=[], help="credential env/JSON/YAML file to inspect")
233
- credential_parser.add_argument("action", nargs="?", default="resolve", choices=["resolve", "backends"])
234
- credential_parser.add_argument("provider", nargs="?")
235
-
236
- source_parser = subparsers.add_parser("source", help="manage reusable provider/project sources")
237
- source_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
238
- source_parser.add_argument("action", nargs="?", default="list", choices=["list", "add", "status", "remove"])
239
- source_parser.add_argument("source_id", nargs="?")
240
- source_parser.add_argument("--provider", help="provider id used by this source")
241
- source_parser.add_argument("--label", help="human-readable source label")
242
- source_parser.add_argument("--config", action="append", default=[], help="source config as KEY=VALUE")
243
- source_parser.add_argument("--env", action="append", default=[], help="environment reference as PROVIDER_ENV=LOCAL_ENV")
244
- source_parser.add_argument("--env-file", action="append", default=[], help="credential file reference")
245
- source_parser.add_argument("--default-for", action="append", default=[], help="intent that should use this source by default")
246
- source_parser.add_argument("--default-for-agent", action="append", default=[], help="agent id that should use this source by default")
247
- source_parser.add_argument("--set-default", action="store_true", help="set as default source for its provider")
248
-
249
- wizard_parser = subparsers.add_parser("wizard", help="continue agentic setup wizards")
250
- wizard_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
251
- wizard_parser.add_argument("action", nargs="?", default="list", choices=["list", "show", "answer", "cancel"])
252
- wizard_parser.add_argument("wizard_id", nargs="?")
253
- wizard_parser.add_argument("answer", nargs="*")
254
- wizard_parser.add_argument("--status", help="filter wizard list by status")
255
- wizard_parser.add_argument("--no-run", action="store_true", help="do not resume the original prompt after completing a wizard")
256
-
257
- memory_parser = subparsers.add_parser("memory", help="inspect or reset local AI DevKit memory")
258
- memory_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
259
- memory_parser.add_argument("action", nargs="?", default="show", choices=["show", "path", "reset"])
260
- memory_parser.add_argument("--agent", dest="agent_id")
261
- memory_parser.add_argument("--source", dest="source_id")
262
- memory_parser.add_argument("--all", action="store_true", help="reset all local memory")
263
- memory_parser.add_argument("--sessions", action="store_true", help="reset local conversation sessions")
264
- memory_parser.add_argument("--tasks", action="store_true", help="reset local task schedules")
265
- memory_parser.add_argument("--cache", action="store_true", help="reset local cache")
266
-
267
- personality_parser = subparsers.add_parser("personality", help="inspect or update local Agent DevKit personality")
268
- personality_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
269
- personality_parser.add_argument("action", nargs="?", default="show", choices=["show", "edit", "reset"])
270
- personality_parser.add_argument("--name", dest="agent_name", help="public agent name")
271
- personality_parser.add_argument("--user-name", help="user name")
272
- personality_parser.add_argument("--language", help="default response language")
273
- personality_parser.add_argument("--tone", help="response tone")
274
- personality_parser.add_argument("--detail-level", help="response detail level")
275
-
276
- setup_parser = subparsers.add_parser("setup", help="run setup helpers")
277
- setup_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
278
- setup_parser.add_argument("--dry-run", action="store_true", help="show setup plan without installing external tools")
279
- setup_parser.add_argument("--yes", action="store_true", help="confirm setup actions")
280
- setup_parser.add_argument("action", nargs="?", default="plan", choices=["plan", "personality"])
281
-
282
- alias_parser = subparsers.add_parser("alias", help="manage local command aliases for agent")
283
- alias_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
284
- alias_parser.add_argument("action", nargs="?", default="list", choices=["add", "list", "remove", "sync"])
285
- alias_parser.add_argument("name", nargs="?")
286
- alias_parser.add_argument("--force", action="store_true", help="allow replacing an existing local alias file")
287
-
288
- session_parser = subparsers.add_parser("session", help="manage local conversation sessions")
289
- session_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
290
- session_parser.add_argument("action", nargs="?", default="list", choices=["list", "show", "resume"])
291
- session_parser.add_argument("session_id", nargs="?")
292
-
293
- toolchain_parser = subparsers.add_parser("toolchain", help="inspect or install external tools")
294
- toolchain_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
295
- toolchain_parser.add_argument("action", nargs="?", default="list", choices=["list", "doctor", "install"])
296
- toolchain_parser.add_argument("tool", nargs="?", default="all")
297
- toolchain_parser.add_argument("--dry-run", action="store_true", help="show install plan without executing it")
298
- toolchain_parser.add_argument("--yes", action="store_true", help="confirm external tool installation")
299
-
300
- task_parser = subparsers.add_parser("task", help="manage local scheduled tasks")
301
- task_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
302
- task_parser.add_argument("action", nargs="?", default="list", choices=["create", "list", "show", "history", "run", "pause", "resume", "update", "enable", "disable", "delete"])
303
- task_parser.add_argument("task_id", nargs="?")
304
- task_parser.add_argument("--title")
305
- task_parser.add_argument("--prompt")
306
- task_parser.add_argument("--every")
307
- task_parser.add_argument("--cron")
308
- task_parser.add_argument("--dry-run", action="store_true")
309
- task_parser.add_argument("--yes", action="store_true")
310
-
311
- scheduler_parser = subparsers.add_parser("scheduler", help="run local scheduler")
312
- scheduler_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
313
- scheduler_parser.add_argument("action", nargs="?", default="run-once", choices=["run-once", "daemon"])
314
- scheduler_parser.add_argument("--dry-run", action="store_true")
315
-
316
- calendar_parser = subparsers.add_parser("calendar", help="inspect configured calendar")
317
- calendar_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
318
- calendar_parser.add_argument("action", nargs="?", default="today", choices=["today", "tomorrow", "list", "configure"])
319
- calendar_parser.add_argument("--from", dest="date_from")
320
- calendar_parser.add_argument("--to", dest="date_to")
321
- calendar_parser.add_argument("--ics")
322
- calendar_parser.add_argument("--timezone")
323
-
324
- pr_parser = subparsers.add_parser("pr", help="review GitHub pull requests")
325
- pr_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
326
- pr_parser.add_argument("action", nargs="?", default="list-review-requests", choices=["list-review-requests", "inspect", "review", "automation"])
327
- pr_parser.add_argument("pr_ref", nargs="?")
328
- pr_parser.add_argument("automation_action", nargs="?")
329
- pr_parser.add_argument("--approve", action="store_true")
330
- pr_parser.add_argument("--request-changes", action="store_true")
331
- pr_parser.add_argument("--comment")
332
- pr_parser.add_argument("--allow-write", action="store_true")
333
- pr_parser.add_argument("--dry-run", action="store_true")
334
- pr_parser.add_argument("--time", default="09:00")
335
-
336
- permissions_parser = subparsers.add_parser("permissions", help="manage local permission policies")
337
- permissions_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
338
- permissions_parser.add_argument("action", nargs="?", default="show", choices=["show", "grant", "revoke"])
339
- permissions_parser.add_argument("agent", nargs="?")
340
- permissions_parser.add_argument("provider", nargs="?")
341
- permissions_parser.add_argument("level", nargs="?")
342
- permissions_parser.add_argument("--project")
343
- permissions_parser.add_argument("--task", dest="task_id")
344
-
345
- audit_parser = subparsers.add_parser("audit", help="inspect local execution audit trail")
346
- audit_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
347
- audit_parser.add_argument("action", nargs="?", default="list", choices=["list", "show", "export"])
348
- audit_parser.add_argument("execution_id", nargs="?")
349
- audit_parser.add_argument("--limit", type=int, default=20)
350
- audit_parser.add_argument("--format", default="md", choices=["md", "json"])
351
-
352
- config_parser = subparsers.add_parser("config", help="inspect local Agent DevKit configuration")
353
- config_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
354
- config_parser.add_argument("action", nargs="?", default="show", choices=["show", "path", "migrate-home"])
355
- config_parser.add_argument("--dry-run", action="store_true", help="plan home migration without moving files")
356
-
357
- for command_name, help_text in (
358
- ("tools", "manage enabled local tools"),
359
- ("integrations", "manage provider integration decisions"),
360
- ("skills", "manage local skill decisions"),
361
- ):
362
- control_parser = subparsers.add_parser(command_name, help=help_text)
363
- control_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
364
- control_parser.add_argument("action", nargs="?", default="list", choices=["list", "enable", "disable"])
365
- control_parser.add_argument("item_id", nargs="?")
366
-
367
- decisions_parser = subparsers.add_parser("decisions", help="inspect or reset local opt-in and opt-out decisions")
368
- decisions_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
369
- decisions_parser.add_argument("action", nargs="?", default="list", choices=["list", "forget", "reset"])
370
- decisions_parser.add_argument("item_id", nargs="?")
371
- decisions_parser.add_argument("--category", choices=["tools", "integrations", "skills", "llms"])
372
-
373
- ollama_parser = subparsers.add_parser("ollama", help="inspect and manage local Ollama models")
374
- ollama_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
375
- ollama_parser.add_argument("action", nargs="?", default="status", choices=["status", "models", "pull", "update"])
376
- ollama_parser.add_argument("model", nargs="?")
377
- ollama_parser.add_argument("--yes", action="store_true", help="confirm Ollama model or update operation")
378
- ollama_parser.add_argument("--dry-run", action="store_true", help="show Ollama operation without executing it")
379
-
380
- llm_parser = subparsers.add_parser("llm", help="manage LLM backends")
381
- llm_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
382
- llm_parser.add_argument(
383
- "action",
384
- nargs="?",
385
- default="list",
386
- choices=["list", "doctor", "configure", "set-default", "default", "enable", "disable", "preference"],
387
- )
388
- llm_parser.add_argument("backend", nargs="?")
389
- llm_parser.add_argument("preference_value", nargs="?")
390
- llm_parser.add_argument("--api-key-env", help="environment variable that stores the API key")
391
- llm_parser.add_argument("--base-url", help="OpenAI-compatible base URL")
392
- llm_parser.add_argument("--model", help="default model id")
393
- llm_parser.add_argument("--command", dest="host_command", help="host CLI command name or path")
394
- llm_parser.add_argument("--set-default", action="store_true", help="set backend as the default LLM")
395
- llm_parser.add_argument("--primary", help="primary backend for LLM preference")
396
- llm_parser.add_argument("--order", help="comma-separated fallback order")
397
-
398
- install_parser = subparsers.add_parser("install", help="install AI DevKit host artifacts")
399
- install_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
400
- install_parser.add_argument("scope", nargs="?", default="project", choices=["project", "global"])
401
- install_parser.add_argument("--target", help="project directory for project installs")
402
- install_parser.add_argument("--home", help="home directory override for global installs")
403
- install_parser.add_argument(
404
- "--host",
405
- default="all",
406
- choices=["all", "codex", "claude-code", "claude-desktop", "claude-ai"],
407
- help="host adapter to install",
408
- )
409
- install_parser.add_argument("--profiles", help="comma-separated project profiles to record in the lock")
410
- install_parser.add_argument("--dry-run", action="store_true", help="print planned writes without creating files")
411
-
412
- agents_parser = subparsers.add_parser("agents", aliases=["a"], help="list available agents")
413
- agents_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
414
- agents_parser.add_argument("action", nargs="?", default="list", choices=["list"])
415
-
416
- capabilities_parser = subparsers.add_parser(
417
- "capabilities",
418
- aliases=["c"],
419
- help="list capabilities",
420
- )
421
- capabilities_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
422
- capabilities_parser.add_argument("action_or_agent", nargs="?", default="list")
423
- capabilities_parser.add_argument("legacy_agent", nargs="?")
424
- capabilities_parser.add_argument("--agent", dest="agent")
425
-
426
- inspect_parser = subparsers.add_parser(
427
- "inspect",
428
- aliases=["i"],
429
- help="inspect an agent capability",
430
- )
431
- inspect_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
432
- inspect_parser.add_argument("agent")
433
- inspect_parser.add_argument("capability")
434
-
435
- run_parser = subparsers.add_parser(
436
- "run",
437
- aliases=["r"],
438
- help="run an agent capability",
439
- )
440
- run_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
441
- run_parser.add_argument("agent")
442
- run_parser.add_argument("capability")
443
- run_parser.add_argument("capability_args", nargs=argparse.REMAINDER)
444
-
445
- doctor_parser = subparsers.add_parser("doctor", help="run local diagnostics")
446
- doctor_parser.add_argument("--json", action="store_true", default=argparse.SUPPRESS, help=argparse.SUPPRESS)
447
- doctor_parser.add_argument("--scope", default="auto", choices=["auto", "project", "global"], help="diagnostic scope")
448
- doctor_parser.add_argument("--project", help="project directory whose AI DevKit lock should be checked")
449
- doctor_parser.add_argument("--home", help="home directory override for global lock checks")
450
- return parser
451
-
452
-
453
- def dispatch(args: argparse.Namespace) -> dict[str, Any] | None:
454
- if args.version:
455
- return {"kind": "version", "program": getattr(args, "prog_name", "aikit"), "version": __version__}
456
- if args.sessions_shortcut:
457
- return list_sessions()
458
-
459
- if not args.command:
460
- raise DevKitError("missing command. Use --help for usage.")
461
-
462
- command = canonical_command(args.command)
463
- if command == "agent":
464
- return agent_requires_llm(args)
465
- if command == "commands":
466
- return list_command_modes()
467
- if command == "providers":
468
- return dispatch_providers(args)
469
- if command == "provider":
470
- return dispatch_provider(args)
471
- if command == "credential":
472
- return dispatch_credential(args)
473
- if command == "source":
474
- return dispatch_source(args)
475
- if command == "wizard":
476
- return dispatch_wizard(args)
477
- if command == "memory":
478
- return dispatch_memory(args)
479
- if command == "personality":
480
- return dispatch_personality(args)
481
- if command == "setup":
482
- return dispatch_setup(args)
483
- if command == "alias":
484
- return dispatch_alias(args)
485
- if command == "session":
486
- return dispatch_session(args)
487
- if command == "toolchain":
488
- return dispatch_toolchain(args)
489
- if command == "task":
490
- return dispatch_task(args)
491
- if command == "scheduler":
492
- return dispatch_scheduler(args)
493
- if command == "calendar":
494
- return dispatch_calendar(args)
495
- if command == "pr":
496
- return dispatch_pr(args)
497
- if command == "permissions":
498
- return dispatch_permissions(args)
499
- if command == "audit":
500
- return dispatch_audit(args)
501
- if command == "config":
502
- return dispatch_config(args)
503
- if command in {"tools", "integrations", "skills"}:
504
- return dispatch_control_category(command, args)
505
- if command == "decisions":
506
- return dispatch_decisions(args)
507
- if command == "ollama":
508
- return dispatch_ollama(args)
509
- if command == "llm":
510
- return dispatch_llm(args)
511
- if command == "install":
512
- return dispatch_install(args)
513
- if command == "agents":
514
- return {"kind": "agents", "items": list_agents()}
515
- if command == "capabilities":
516
- agent_id = resolve_capabilities_agent(args)
517
- if agent_id:
518
- agent = load_agent(agent_id)
519
- return {
520
- "kind": "capabilities",
521
- "agent": agent["id"],
522
- "items": list_capabilities(agent["path"]),
523
- }
524
- return {
525
- "kind": "capabilities",
526
- "agent": None,
527
- "items": list_all_capabilities(),
528
- }
529
- if command == "inspect":
530
- agent = load_agent(args.agent)
531
- capability = load_capability(agent["path"], args.capability)
532
- return {
533
- "kind": "capability",
534
- "agent": summarize_agent(agent),
535
- "capability": capability,
536
- }
537
- if command == "run":
538
- agent = load_agent(args.agent)
539
- return run_capability(
540
- agent,
541
- args.capability,
542
- args.capability_args,
543
- capture_output=args.json,
544
- )
545
- if command == "doctor":
546
- return doctor(args.project, args.home, args.scope)
547
- raise DevKitError(f"unsupported command: {args.command}")
548
-
549
-
550
- def canonical_command(command: str) -> str:
551
- aliases = {
552
- "a": "agents",
553
- "c": "capabilities",
554
- "i": "inspect",
555
- "r": "run",
556
- }
557
- return aliases.get(command, command)
558
-
559
-
560
- def list_command_modes() -> dict[str, Any]:
561
- return {
562
- "kind": "commands",
563
- "deterministic": [
564
- {
565
- "command": command,
566
- "requires_llm": False,
567
- }
568
- for command in DETERMINISTIC_COMMANDS
569
- ],
570
- "llm": [
571
- {
572
- "command": command,
573
- "requires_llm": True,
574
- }
575
- for command in LLM_COMMANDS
576
- ],
577
- }
578
-
579
-
580
- def maybe_record_cli_audit(args: argparse.Namespace, *, result: dict[str, Any] | None, error: str | None) -> None:
581
- command = canonical_command(getattr(args, "command", None) or "")
582
- if command in {"", "audit"} or getattr(args, "version", False):
583
- return
584
- try:
585
- audit = record_audit(command=command, args=vars(args), result=result, error=error)
586
- except Exception:
587
- return
588
- if result is not None:
589
- result["audit"] = audit
590
-
591
-
592
- def dispatch_llm(args: argparse.Namespace) -> dict[str, Any]:
593
- try:
594
- if args.action != "preference" and args.preference_value:
595
- raise DevKitError(f"llm {args.action} received an unexpected argument: {args.preference_value}")
596
- if args.action == "list":
597
- if args.backend:
598
- raise DevKitError("llm list does not accept a backend argument")
599
- return list_backends()
600
- if args.action == "doctor":
601
- return doctor_backends(args.backend)
602
- if args.action == "configure":
603
- if not args.backend:
604
- raise DevKitError("llm configure requires a backend")
605
- return configure_backend(
606
- args.backend,
607
- api_key_env=args.api_key_env,
608
- base_url=args.base_url,
609
- model=args.model,
610
- command=args.host_command,
611
- set_default=args.set_default,
612
- )
613
- if args.action in {"set-default", "default"}:
614
- if not args.backend:
615
- raise DevKitError(f"llm {args.action} requires a backend")
616
- return set_default_backend(args.backend)
617
- if args.action in {"enable", "disable"}:
618
- if not args.backend:
619
- raise DevKitError(f"llm {args.action} requires a backend")
620
- state = "enabled" if args.action == "enable" else "disabled_by_user"
621
- return set_decision("llms", args.backend, state, reason=f"llm {args.action} command")
622
- if args.action == "preference":
623
- if args.backend in {None, "show"}:
624
- return llm_preference()
625
- if args.backend == "set":
626
- if not args.primary and not args.order:
627
- raise DevKitError("llm preference set requires --primary or --order")
628
- return set_llm_preference(primary=args.primary, order=args.order)
629
- if args.backend == "reorder":
630
- order = args.preference_value or args.order
631
- if not order:
632
- raise DevKitError("llm preference reorder requires an order value or --order")
633
- return set_llm_preference(order=order)
634
- raise DevKitError("llm preference action must be show, set or reorder")
635
- except ValueError as exc:
636
- raise DevKitError(str(exc)) from exc
637
- raise DevKitError(f"unsupported llm action: {args.action}")
638
-
639
-
640
- def dispatch_config(args: argparse.Namespace) -> dict[str, Any]:
641
- from cli.aikit.llm import config_path
642
-
643
- if args.action == "path":
644
- return {"kind": "config", "status": "ok", "path": str(config_path()), "home": app_home_status()}
645
- if args.action == "migrate-home":
646
- return migrate_default_home(dry_run=effective_dry_run(args))
647
- if args.action == "show":
648
- return {
649
- "kind": "config",
650
- "status": "ok",
651
- "path": str(config_path()),
652
- "home": app_home_status(),
653
- "decisions": list_decisions(),
654
- "llm": llm_preference(),
655
- "ollama": ollama_status(),
656
- }
657
- raise DevKitError(f"unsupported config action: {args.action}")
658
-
659
-
660
- def dispatch_control_category(command: str, args: argparse.Namespace) -> dict[str, Any]:
661
- try:
662
- category = command
663
- if args.action == "list":
664
- if args.item_id:
665
- raise DevKitError(f"{command} list does not accept an item id")
666
- payload = list_decisions(category)
667
- payload["kind"] = command
668
- return payload
669
- if args.action in {"enable", "disable"}:
670
- if not args.item_id:
671
- raise DevKitError(f"{command} {args.action} requires an item id")
672
- state = "enabled" if args.action == "enable" else "disabled_by_user"
673
- payload = set_decision(category, args.item_id, state, reason=f"{command} {args.action} command")
674
- payload["kind"] = command[:-1] if command.endswith("s") else command
675
- return payload
676
- except ValueError as exc:
677
- raise DevKitError(str(exc)) from exc
678
- raise DevKitError(f"unsupported {command} action: {args.action}")
679
-
680
-
681
- def dispatch_decisions(args: argparse.Namespace) -> dict[str, Any]:
682
- try:
683
- if args.action == "list":
684
- if args.item_id:
685
- raise DevKitError("decisions list does not accept an item id")
686
- return list_decisions(args.category)
687
- if args.action == "reset":
688
- if args.item_id:
689
- raise DevKitError("decisions reset does not accept an item id")
690
- return reset_decisions(args.category)
691
- if args.action == "forget":
692
- if not args.item_id:
693
- raise DevKitError("decisions forget requires an item id")
694
- category = args.category or "tools"
695
- return forget_decision(category, args.item_id)
696
- except ValueError as exc:
697
- raise DevKitError(str(exc)) from exc
698
- raise DevKitError(f"unsupported decisions action: {args.action}")
699
-
700
-
701
- def dispatch_ollama(args: argparse.Namespace) -> dict[str, Any]:
702
- try:
703
- if args.action == "status":
704
- if args.model:
705
- raise DevKitError("ollama status does not accept a model")
706
- return ollama_status()
707
- if args.action == "models":
708
- if args.model:
709
- raise DevKitError("ollama models does not accept a model")
710
- return ollama_models()
711
- if args.action == "pull":
712
- return ollama_pull(args.model, yes=args.yes, dry_run=effective_dry_run(args))
713
- if args.action == "update":
714
- if args.model:
715
- raise DevKitError("ollama update does not accept a model")
716
- return ollama_update(yes=args.yes, dry_run=effective_dry_run(args))
717
- except ValueError as exc:
718
- raise DevKitError(str(exc)) from exc
719
- raise DevKitError(f"unsupported ollama action: {args.action}")
720
-
721
-
722
- def dispatch_install(args: argparse.Namespace) -> dict[str, Any]:
723
- try:
724
- return install_runtime(
725
- ROOT,
726
- scope=args.scope,
727
- host=args.host,
728
- target=Path(args.target) if args.target else None,
729
- home=Path(args.home) if args.home else None,
730
- dry_run=effective_dry_run(args),
731
- profiles=parse_profiles(args.profiles),
732
- )
733
- except InstallError as exc:
734
- raise DevKitError(str(exc)) from exc
735
-
736
-
737
- def dispatch_providers(args: argparse.Namespace) -> dict[str, Any]:
738
- if args.action != "list":
739
- raise DevKitError(f"unsupported providers action: {args.action}")
740
- try:
741
- return list_providers(ROOT)
742
- except ProviderRegistryError as exc:
743
- raise DevKitError(str(exc)) from exc
744
-
745
-
746
- def dispatch_provider(args: argparse.Namespace) -> dict[str, Any]:
747
- try:
748
- if args.action in {"status", "doctor"}:
749
- return provider_status_with_credentials(ROOT, args.provider, env_files=[Path(item) for item in args.env_file])
750
- if args.action == "configure":
751
- if not args.provider:
752
- raise DevKitError("provider configure requires a provider id")
753
- return configure_provider(
754
- ROOT,
755
- args.provider,
756
- env_refs=args.env,
757
- env_files=[Path(item) for item in args.env_file],
758
- from_env=args.from_env,
759
- session_only=args.session_only,
760
- )
761
- if args.action == "unset":
762
- if not args.provider:
763
- raise DevKitError("provider unset requires a provider id")
764
- return unset_provider_config(ROOT, args.provider)
765
- except ProviderRegistryError as exc:
766
- raise DevKitError(str(exc)) from exc
767
- except CredentialResolverError as exc:
768
- raise DevKitError(str(exc)) from exc
769
- raise DevKitError(f"unsupported provider action: {args.action}")
770
-
771
-
772
- def dispatch_credential(args: argparse.Namespace) -> dict[str, Any]:
773
- if args.action == "backends":
774
- if args.provider:
775
- raise DevKitError("credential backends does not accept a provider argument")
776
- return credential_backends()
777
- if args.action == "resolve":
778
- if not args.provider:
779
- raise DevKitError("credential resolve requires a provider id")
780
- try:
781
- return credential_resolution(ROOT, args.provider, env_files=[Path(item) for item in args.env_file])
782
- except (ProviderRegistryError, CredentialResolverError) as exc:
783
- raise DevKitError(str(exc)) from exc
784
- raise DevKitError(f"unsupported credential action: {args.action}")
785
-
786
-
787
- def dispatch_source(args: argparse.Namespace) -> dict[str, Any]:
788
- try:
789
- if args.action == "list":
790
- return list_sources()
791
- if args.action == "add":
792
- if not args.source_id:
793
- raise DevKitError("source add requires a source id")
794
- return add_source(
795
- args.source_id,
796
- provider=args.provider,
797
- label=args.label,
798
- config_pairs=args.config,
799
- env_refs=args.env,
800
- env_files=args.env_file,
801
- default_for=args.default_for,
802
- default_for_agent=args.default_for_agent,
803
- set_default=args.set_default,
804
- )
805
- if args.action == "status":
806
- return source_status(args.source_id)
807
- if args.action == "remove":
808
- if not args.source_id:
809
- raise DevKitError("source remove requires a source id")
810
- return remove_source(args.source_id)
811
- except SourceRegistryError as exc:
812
- raise DevKitError(str(exc)) from exc
813
- raise DevKitError(f"unsupported source action: {args.action}")
814
-
815
-
816
- def dispatch_wizard(args: argparse.Namespace) -> dict[str, Any]:
817
- try:
818
- if args.action == "list":
819
- return list_wizards(status=args.status)
820
- if args.action == "show":
821
- require_id(args.wizard_id, "wizard show")
822
- return show_wizard(args.wizard_id)
823
- if args.action == "cancel":
824
- require_id(args.wizard_id, "wizard cancel")
825
- return cancel_wizard(args.wizard_id)
826
- if args.action == "answer":
827
- require_id(args.wizard_id, "wizard answer")
828
- answer = " ".join(args.answer or []).strip()
829
- if not answer:
830
- raise DevKitError("wizard answer requires an answer")
831
- payload = answer_wizard(args.wizard_id, answer)
832
- if payload.get("status") == "completed" and not args.no_run:
833
- resume_prompt = payload.get("resume_prompt") or (payload.get("wizard") or {}).get("resume_prompt")
834
- if resume_prompt:
835
- payload["resumed_prompt"] = True
836
- payload["resume_result"] = resume_agent_prompt(str(resume_prompt))
837
- else:
838
- payload["resumed_prompt"] = False
839
- else:
840
- payload.setdefault("resumed_prompt", False)
841
- return payload
842
- except WizardStateError as exc:
843
- raise DevKitError(str(exc)) from exc
844
- except SourceRegistryError as exc:
845
- raise DevKitError(str(exc)) from exc
846
- raise DevKitError(f"unsupported wizard action: {args.action}")
847
-
848
-
849
- def maybe_run_interactive_wizard(result: dict[str, Any]) -> dict[str, Any]:
850
- if not sys.stdin.isatty() or not sys.stdout.isatty():
851
- return result
852
- wizard = result.get("setup_wizard") if isinstance(result.get("setup_wizard"), dict) else None
853
- if not wizard or not wizard.get("wizard_id") or result.get("status") != "needs-input":
854
- return result
855
- print(result.get("message") or "O agente precisa de configuracao antes de continuar.")
856
- return run_interactive_wizard(str(wizard["wizard_id"]))
857
-
858
-
859
- def run_interactive_wizard(wizard_id: str) -> dict[str, Any]:
860
- payload = show_wizard(wizard_id)
861
- while True:
862
- wizard = payload.get("wizard") if isinstance(payload.get("wizard"), dict) else {}
863
- question = payload.get("next_question") or wizard.get("next_question")
864
- if not isinstance(question, dict):
865
- return payload
866
- print_interactive_question(question)
867
- try:
868
- answer = input("> ")
869
- except (EOFError, KeyboardInterrupt):
870
- print()
871
- return cancel_wizard(wizard_id, reason="interactive wizard interrupted")
872
- if answer.strip().lower() in {"cancelar", "cancel", "sair", "exit"}:
873
- return cancel_wizard(wizard_id, reason="interactive wizard cancelled by user")
874
- try:
875
- payload = answer_wizard(wizard_id, answer)
876
- except WizardStateError as exc:
877
- print(f"Erro: {exc}")
878
- continue
879
- if payload.get("status") == "completed":
880
- resume_prompt = payload.get("resume_prompt") or (payload.get("wizard") or {}).get("resume_prompt")
881
- if resume_prompt:
882
- payload["resumed_prompt"] = True
883
- payload["resume_result"] = resume_agent_prompt(str(resume_prompt))
884
- else:
885
- payload["resumed_prompt"] = False
886
- return payload
887
- if payload.get("status") in {"cancelled", "denied-by-user", "failed"}:
888
- payload.setdefault("resumed_prompt", False)
889
- return payload
890
-
891
-
892
- def print_interactive_question(question: dict[str, Any]) -> None:
893
- text = question.get("text") or "Informe a resposta."
894
- print(f"\nPergunta: {text}")
895
- if question.get("type") == "confirm":
896
- print("[s/N]")
897
- options = question.get("options")
898
- if isinstance(options, list) and options:
899
- print("Opcoes: " + ", ".join(str(item) for item in options))
900
- if question.get("suggested_value"):
901
- print(f"Sugestao: {question['suggested_value']}")
902
- if question.get("env_ref_key"):
903
- print("Informe o nome da variavel de ambiente, nao o valor da credencial.")
904
- print("Digite 'cancelar' para interromper.")
905
-
906
-
907
- def resume_agent_prompt(prompt: str) -> dict[str, Any]:
908
- args = argparse.Namespace(
909
- command="agent",
910
- prompt=prompt.split(),
911
- session_id=None,
912
- new_session=False,
913
- llm=None,
914
- no_llm_fallback=False,
915
- dry_run=False,
916
- global_dry_run=False,
917
- prog_name="agent",
918
- json=True,
919
- version=False,
920
- sessions_shortcut=False,
921
- )
922
- result = agent_requires_llm(args)
923
- result.pop("audit", None)
924
- return result
925
-
926
-
927
- def dispatch_memory(args: argparse.Namespace) -> dict[str, Any]:
928
- if args.action == "show":
929
- return show_memory(ROOT, agent_id=args.agent_id, source_id=args.source_id)
930
- if args.action == "path":
931
- return memory_path_payload()
932
- if args.action == "reset":
933
- return reset_memory(
934
- all_memory=args.all,
935
- agent_id=args.agent_id,
936
- source_id=args.source_id,
937
- reset_sessions=args.sessions,
938
- reset_tasks=args.tasks,
939
- reset_cache=args.cache,
940
- )
941
- raise DevKitError(f"unsupported memory action: {args.action}")
942
-
943
-
944
- def dispatch_personality(args: argparse.Namespace) -> dict[str, Any]:
945
- if args.action == "show":
946
- return load_personality()
947
- if args.action == "edit":
948
- if not any([args.agent_name, args.user_name, args.language, args.tone, args.detail_level]):
949
- payload = load_personality()
950
- payload["status"] = "needs-input"
951
- payload["message"] = "Use --name, --user-name, --language, --tone or --detail-level to edit non-interactively."
952
- return payload
953
- return update_personality(
954
- agent_name=args.agent_name,
955
- user_name=args.user_name,
956
- language=args.language,
957
- tone=args.tone,
958
- detail_level=args.detail_level,
959
- )
960
- if args.action == "reset":
961
- return reset_personality()
962
- raise DevKitError(f"unsupported personality action: {args.action}")
963
-
964
-
965
- def dispatch_setup(args: argparse.Namespace) -> dict[str, Any]:
966
- if args.action == "personality":
967
- return setup_personality()
968
- if args.action == "plan":
969
- return setup_wizard(ROOT, dry_run=effective_dry_run(args), yes=args.yes)
970
- raise DevKitError(f"unsupported setup action: {args.action}")
971
-
972
-
973
- def dispatch_toolchain(args: argparse.Namespace) -> dict[str, Any]:
974
- try:
975
- if args.action == "list":
976
- if args.tool != "all":
977
- raise DevKitError("toolchain list does not accept a tool argument")
978
- return list_toolchain(ROOT)
979
- if args.action == "doctor":
980
- return doctor_toolchain(ROOT, None if args.tool == "all" else args.tool)
981
- if args.action == "install":
982
- return install_toolchain(ROOT, None if args.tool == "all" else args.tool, dry_run=effective_dry_run(args), yes=args.yes)
983
- except ValueError as exc:
984
- raise DevKitError(str(exc)) from exc
985
- raise DevKitError(f"unsupported toolchain action: {args.action}")
986
-
987
-
988
- def dispatch_task(args: argparse.Namespace) -> dict[str, Any]:
989
- try:
990
- if args.action == "list":
991
- return list_tasks()
992
- if args.action == "create":
993
- schedule = {"type": "manual"}
994
- if args.every:
995
- schedule = {"type": "interval", "every": args.every}
996
- if args.cron:
997
- schedule = {"type": "cron", "cron": args.cron}
998
- return create_task(task_id=args.task_id, title=args.title, prompt=args.prompt, schedule=schedule)
999
- if args.action == "show":
1000
- require_id(args.task_id, "task show")
1001
- return show_task(args.task_id)
1002
- if args.action == "history":
1003
- require_id(args.task_id, "task history")
1004
- return task_history(args.task_id)
1005
- if args.action == "run":
1006
- require_id(args.task_id, "task run")
1007
- return run_task(args.task_id, dry_run=effective_dry_run(args))
1008
- if args.action in {"pause", "disable"}:
1009
- require_id(args.task_id, f"task {args.action}")
1010
- return update_task_status(args.task_id, "paused" if args.action == "pause" else "disabled")
1011
- if args.action in {"resume", "enable"}:
1012
- require_id(args.task_id, f"task {args.action}")
1013
- return update_task_status(args.task_id, "enabled")
1014
- if args.action == "update":
1015
- require_id(args.task_id, "task update")
1016
- return update_task_schedule(args.task_id, every=args.every, cron=args.cron)
1017
- if args.action == "delete":
1018
- require_id(args.task_id, "task delete")
1019
- return delete_task(args.task_id, yes=args.yes)
1020
- except ValueError as exc:
1021
- raise DevKitError(str(exc)) from exc
1022
- raise DevKitError(f"unsupported task action: {args.action}")
1023
-
1024
-
1025
- def dispatch_scheduler(args: argparse.Namespace) -> dict[str, Any]:
1026
- if args.action == "run-once":
1027
- return run_scheduler_once(dry_run=effective_dry_run(args))
1028
- if args.action == "daemon":
1029
- return scheduler_daemon_plan()
1030
- raise DevKitError(f"unsupported scheduler action: {args.action}")
1031
-
1032
-
1033
- def dispatch_calendar(args: argparse.Namespace) -> dict[str, Any]:
1034
- try:
1035
- if args.action == "configure":
1036
- return configure_calendar(ics_path=args.ics, timezone=args.timezone)
1037
- if args.action == "today":
1038
- return calendar_today()
1039
- if args.action == "tomorrow":
1040
- return calendar_tomorrow()
1041
- if args.action == "list":
1042
- return calendar_list(args.date_from, args.date_to)
1043
- except ValueError as exc:
1044
- raise DevKitError(str(exc)) from exc
1045
- raise DevKitError(f"unsupported calendar action: {args.action}")
1046
-
1047
-
1048
- def dispatch_pr(args: argparse.Namespace) -> dict[str, Any]:
1049
- if args.action == "list-review-requests":
1050
- if effective_dry_run(args):
1051
- return pr_read_dry_run("list-review-requests")
1052
- return pr_list_review_requests()
1053
- if args.action == "inspect":
1054
- require_id(args.pr_ref, "pr inspect")
1055
- if effective_dry_run(args):
1056
- return pr_read_dry_run("inspect", pr_ref=args.pr_ref)
1057
- return pr_inspect(args.pr_ref)
1058
- if args.action == "review":
1059
- require_id(args.pr_ref, "pr review")
1060
- return pr_review(
1061
- args.pr_ref,
1062
- approve=args.approve,
1063
- request_changes=args.request_changes,
1064
- comment=args.comment,
1065
- allow_write=args.allow_write,
1066
- dry_run=effective_dry_run(args),
1067
- )
1068
- if args.action == "automation":
1069
- if args.automation_action not in {None, "create"}:
1070
- raise DevKitError("pr automation action must be create")
1071
- if effective_dry_run(args):
1072
- return pr_automation_dry_run(time=args.time)
1073
- return pr_create_automation(time=args.time)
1074
- raise DevKitError(f"unsupported pr action: {args.action}")
1075
-
1076
-
1077
- def dispatch_permissions(args: argparse.Namespace) -> dict[str, Any]:
1078
- try:
1079
- if args.action == "show":
1080
- return show_permissions()
1081
- if args.action == "grant":
1082
- if not args.agent or not args.provider or not args.level:
1083
- raise DevKitError("permissions grant requires agent, provider and level")
1084
- return grant_permission(args.agent, args.provider, args.level, project=args.project, task_id=args.task_id)
1085
- if args.action == "revoke":
1086
- if not args.agent or not args.provider:
1087
- raise DevKitError("permissions revoke requires agent and provider")
1088
- return revoke_permission(args.agent, args.provider, args.level, project=args.project, task_id=args.task_id)
1089
- except ValueError as exc:
1090
- raise DevKitError(str(exc)) from exc
1091
- raise DevKitError(f"unsupported permissions action: {args.action}")
1092
-
1093
-
1094
- def dispatch_audit(args: argparse.Namespace) -> dict[str, Any]:
1095
- try:
1096
- if args.action == "list":
1097
- if args.execution_id:
1098
- raise DevKitError("audit list does not accept an execution id")
1099
- return list_audits(limit=max(1, int(args.limit or 20)))
1100
- if args.action == "show":
1101
- require_id(args.execution_id, "audit show")
1102
- return show_audit(args.execution_id)
1103
- if args.action == "export":
1104
- require_id(args.execution_id, "audit export")
1105
- return export_audit(args.execution_id, fmt=args.format)
1106
- except ValueError as exc:
1107
- raise DevKitError(str(exc)) from exc
1108
- raise DevKitError(f"unsupported audit action: {args.action}")
1109
-
1110
-
1111
- def pr_read_dry_run(action: str, *, pr_ref: str | None = None) -> dict[str, Any]:
1112
- return {
1113
- "kind": "pr",
1114
- "status": "planned",
1115
- "ok": True,
1116
- "dry_run": True,
1117
- "mode": "report-only",
1118
- "provider": "github",
1119
- "action": action,
1120
- "pr_ref": pr_ref,
1121
- "commands": planned_pr_commands(action, pr_ref=pr_ref),
1122
- "summary": "Dry-run only. GitHub would be read through gh; no PR write action would be submitted.",
1123
- }
1124
-
1125
-
1126
- def pr_automation_dry_run(*, time: str) -> dict[str, Any]:
1127
- return {
1128
- "kind": "pr-automation",
1129
- "status": "planned",
1130
- "ok": True,
1131
- "dry_run": True,
1132
- "mode": "report-only",
1133
- "provider": "github",
1134
- "task": {
1135
- "id": "daily-pr-review",
1136
- "title": "Revisar PRs pendentes diariamente",
1137
- "schedule": {"type": "daily", "time": time},
1138
- "action": {
1139
- "type": "capability",
1140
- "agent": "github-pr-reviewer",
1141
- "capability": "list-review-requests",
1142
- "external_writes": False,
1143
- },
1144
- "permissions": {"mode": "report-only", "comment": False, "approve": False, "request_changes": False},
1145
- },
1146
- "summary": "Dry-run only. A local report-only PR review task would be created.",
1147
- }
1148
-
1149
-
1150
- def planned_pr_commands(action: str, *, pr_ref: str | None = None) -> list[list[str]]:
1151
- if action == "list-review-requests":
1152
- return [["gh", "pr", "list", "--review-requested", "@me", "--json", "number,title,url,author,headRefName,baseRefName,isDraft"]]
1153
- if action == "inspect":
1154
- return [["gh", "pr", "view", str(pr_ref), "--json", "number,title,url,author,body,headRefName,baseRefName,state,isDraft,reviewDecision,mergeable"]]
1155
- return []
1156
-
1157
-
1158
- def require_id(value: str | None, command: str) -> None:
1159
- if not value:
1160
- raise DevKitError(f"{command} requires an id")
1161
-
1162
-
1163
- def effective_dry_run(args: argparse.Namespace) -> bool:
1164
- return bool(getattr(args, "dry_run", False) or getattr(args, "global_dry_run", False))
1165
-
1166
-
1167
- def dispatch_alias(args: argparse.Namespace) -> dict[str, Any]:
1168
- try:
1169
- if args.action == "list":
1170
- if args.name:
1171
- raise DevKitError("alias list does not accept a name")
1172
- return list_aliases()
1173
- if args.action == "add":
1174
- if not args.name:
1175
- raise DevKitError("alias add requires a name")
1176
- return add_alias(args.name, force=args.force)
1177
- if args.action == "remove":
1178
- if not args.name:
1179
- raise DevKitError("alias remove requires a name")
1180
- return remove_alias(args.name)
1181
- if args.action == "sync":
1182
- if args.name:
1183
- raise DevKitError("alias sync does not accept a name")
1184
- return sync_aliases()
1185
- except ValueError as exc:
1186
- raise DevKitError(str(exc)) from exc
1187
- raise DevKitError(f"unsupported alias action: {args.action}")
1188
-
1189
-
1190
- def dispatch_session(args: argparse.Namespace) -> dict[str, Any]:
1191
- try:
1192
- if args.action == "list":
1193
- if args.session_id:
1194
- raise DevKitError("session list does not accept a session id")
1195
- return list_sessions()
1196
- if args.action == "show":
1197
- if not args.session_id:
1198
- raise DevKitError("session show requires a session id")
1199
- return show_session(args.session_id)
1200
- if args.action == "resume":
1201
- if not args.session_id:
1202
- raise DevKitError("session resume requires a session id")
1203
- return resume_session(args.session_id)
1204
- except ValueError as exc:
1205
- raise DevKitError(str(exc)) from exc
1206
- raise DevKitError(f"unsupported session action: {args.action}")
1207
-
1208
-
1209
- def agent_requires_llm(args: argparse.Namespace) -> dict[str, Any]:
1210
- prompt = " ".join(args.prompt).strip()
1211
- if not prompt:
1212
- raise DevKitError("agent requires a natural-language prompt")
1213
- if effective_dry_run(args):
1214
- return build_agent_dry_run_plan(prompt, args)
1215
- try:
1216
- session = get_or_create_session(
1217
- session_id=args.session_id,
1218
- force_new=args.new_session,
1219
- prompt=prompt,
1220
- project=str(Path.cwd()),
1221
- backend=args.llm,
1222
- )
1223
- except ValueError as exc:
1224
- raise DevKitError(str(exc)) from exc
1225
- personality = load_personality()
1226
- name = public_name(personality=personality, invoked_as=getattr(args, "prog_name", "agent"))
1227
- if is_identity_question(prompt):
1228
- result = {
1229
- "kind": "agent",
1230
- "status": "ok",
1231
- "ok": True,
1232
- "requires_llm": False,
1233
- "prompt_received": True,
1234
- "prompt_length": len(prompt),
1235
- "identity": {"name": name, "source": "local"},
1236
- "response": local_identity_response(prompt, name=name),
1237
- }
1238
- return finalize_agent_session(result, session, prompt, backend=args.llm)
1239
- natural_result = dispatch_natural_operational_prompt(prompt)
1240
- if natural_result:
1241
- return finalize_agent_session(natural_result, session, prompt, backend=args.llm)
1242
- route = route_prompt(prompt)
1243
- if route:
1244
- result = invoke_agentic_route(prompt, route)
1245
- return finalize_agent_session(result, session, prompt, backend=args.llm)
1246
- contextual_prompt = build_contextual_prompt(str(session["id"]), prompt)
1247
- execution_plan = build_execution_plan(ROOT, prompt, dry_run=False)
1248
- if execution_plan.get("configuration_tasks"):
1249
- result = agentic_needs_input_from_plan(prompt, execution_plan)
1250
- return finalize_agent_session(result, session, prompt, backend=args.llm)
1251
- model_plan = execution_plan.get("model_plan") if isinstance(execution_plan.get("model_plan"), dict) else build_model_plan(prompt)
1252
- review_gate = execution_plan.get("review_gate") if isinstance(execution_plan.get("review_gate"), dict) else build_review_gate(prompt, model_plan=model_plan)
1253
- local_llm_execution = maybe_delegate_local_llm(prompt, model_plan)
1254
- coordinator_prompt = enrich_prompt_with_local_result(contextual_prompt, local_llm_execution)
1255
- result = invoke_agent_prompt(
1256
- coordinator_prompt,
1257
- args.llm,
1258
- public_name=name,
1259
- allow_fallback=not args.no_llm_fallback,
1260
- )
1261
- review_result = {
1262
- "kind": "execution-review",
1263
- "agent_id": "execution-reviewer",
1264
- "capability_id": "review-final-output",
1265
- "status": "not-run",
1266
- "ok": False,
1267
- }
1268
- if result.get("ok"):
1269
- result, review_gate, review_result = enforce_execution_review(
1270
- prompt=prompt,
1271
- result=result,
1272
- review_gate=review_gate,
1273
- execution_plan=execution_plan,
1274
- producer_backend=str(result.get("llm_backend") or args.llm or ""),
1275
- )
1276
- if review_result.get("ok"):
1277
- execution_plan = mark_review_task(execution_plan, reviewer=str(review_result.get("llm_backend") or "execution-reviewer"))
1278
- elif review_gate.get("status") == "needs-review":
1279
- execution_plan = mark_review_task_needs_review(execution_plan, review_result)
1280
- result["model_plan"] = model_plan
1281
- result["local_llm_execution"] = local_llm_execution
1282
- result["review_gate"] = review_gate
1283
- result["review_result"] = review_result
1284
- result["review_task"] = execution_plan.get("review_task")
1285
- result["execution_plan"] = execution_plan
1286
- result["orchestration_trace"] = execution_plan.get("trace", [])
1287
- result["prompt_length"] = len(prompt)
1288
- result["session_context_applied"] = contextual_prompt != prompt
1289
- result["local_context_applied"] = coordinator_prompt != contextual_prompt
1290
- if result.get("response"):
1291
- result["response"] = enforce_identity_response(str(result["response"]), prompt, name=name)
1292
- result["identity"] = {"name": name, "source": "local"}
1293
- return finalize_agent_session(result, session, prompt, backend=result.get("llm_backend") or args.llm)
1294
-
1295
-
1296
- def mark_review_task_needs_review(execution_plan: dict[str, Any], review_result: dict[str, Any]) -> dict[str, Any]:
1297
- task = dict(execution_plan.get("review_task") or {})
1298
- if task:
1299
- task["status"] = "needs-review"
1300
- task["reviewer"] = None
1301
- task["message"] = review_result.get("message")
1302
- execution_plan["review_task"] = task
1303
- return execution_plan
1304
-
1305
-
1306
- def agentic_needs_input_from_plan(prompt: str, execution_plan: dict[str, Any]) -> dict[str, Any]:
1307
- configuration_task = next(
1308
- (task for task in execution_plan.get("configuration_tasks") or [] if isinstance(task, dict)),
1309
- {},
1310
- )
1311
- wizard = configuration_task.get("setup_wizard") if isinstance(configuration_task.get("setup_wizard"), dict) else {}
1312
- provider = configuration_task.get("provider") or wizard.get("provider")
1313
- payload = {
1314
- "kind": "agent",
1315
- "status": "needs-input",
1316
- "ok": False,
1317
- "mode": "agentic-plan",
1318
- "prompt_received": True,
1319
- "prompt_length": len(prompt),
1320
- "provider": provider,
1321
- "source_provider": provider,
1322
- "requires_source": True,
1323
- "execution_plan": execution_plan,
1324
- "orchestration_trace": execution_plan.get("trace", []),
1325
- "setup_wizard": wizard,
1326
- "next_question": wizard.get("next_question"),
1327
- "message": wizard.get("message") or "O plano multiagente precisa de configuracao antes de executar.",
1328
- "next_steps": [
1329
- "Responda a pergunta do wizard para autorizar ou negar a configuracao deste provider.",
1330
- "Depois de configurar a fonte, reexecute ou retome o mesmo prompt.",
1331
- ],
1332
- "exit_code": 2,
1333
- }
1334
- return persist_setup_wizard_payload(payload, execution_plan=execution_plan)
1335
-
1336
-
1337
- def persist_setup_wizard_payload(
1338
- payload: dict[str, Any],
1339
- *,
1340
- execution_plan: dict[str, Any] | None = None,
1341
- route: dict[str, Any] | None = None,
1342
- ) -> dict[str, Any]:
1343
- wizard = payload.get("setup_wizard")
1344
- if not isinstance(wizard, dict) or wizard.get("wizard_id"):
1345
- return payload
1346
- persisted = create_provider_wizard(
1347
- wizard,
1348
- execution_plan=execution_plan or payload.get("execution_plan"),
1349
- route=route or payload.get("route"),
1350
- )
1351
- payload["setup_wizard"] = persisted
1352
- payload["next_question"] = persisted.get("next_question")
1353
- if execution_plan and execution_plan.get("configuration_tasks"):
1354
- for task in execution_plan.get("configuration_tasks") or []:
1355
- if isinstance(task, dict) and task.get("provider") == persisted.get("provider"):
1356
- task["setup_wizard"] = persisted
1357
- break
1358
- payload.setdefault("wizard_id", persisted.get("wizard_id"))
1359
- return payload
1360
-
1361
-
1362
- def dispatch_natural_operational_prompt(prompt: str) -> dict[str, Any] | None:
1363
- normalized = " ".join(prompt.lower().split())
1364
- control_result = dispatch_natural_control_prompt(normalized)
1365
- if control_result:
1366
- control_result["prompt_received"] = True
1367
- control_result["prompt_length"] = len(prompt)
1368
- return control_result
1369
- if "agenda" in normalized:
1370
- if "amanha" in normalized or "amanhã" in normalized:
1371
- payload = calendar_tomorrow()
1372
- else:
1373
- payload = calendar_today()
1374
- payload = dict(payload)
1375
- payload["kind"] = "agent"
1376
- payload["mode"] = "calendar-route"
1377
- payload["requires_llm"] = False
1378
- payload["prompt_received"] = True
1379
- payload["prompt_length"] = len(prompt)
1380
- payload["response"] = calendar_summary(payload)
1381
- if payload.get("status") == "needs-input":
1382
- payload["ok"] = False
1383
- else:
1384
- payload["ok"] = True
1385
- return payload
1386
- if has_pr_intent(normalized):
1387
- if any(marker in normalized for marker in ("diariamente", "todo dia", "diaria", "diária", "recorrente")):
1388
- payload = pr_create_automation()
1389
- return {
1390
- "kind": "agent",
1391
- "status": payload.get("status"),
1392
- "ok": True,
1393
- "mode": "pr-automation-route",
1394
- "requires_llm": False,
1395
- "prompt_received": True,
1396
- "prompt_length": len(prompt),
1397
- "response": "Automacao diaria de revisao de PRs criada em modo report-only.",
1398
- "result": payload,
1399
- }
1400
- payload = pr_list_review_requests()
1401
- return {
1402
- "kind": "agent",
1403
- "status": payload.get("status"),
1404
- "ok": payload.get("status") == "ok",
1405
- "mode": "pr-route",
1406
- "requires_llm": False,
1407
- "prompt_received": True,
1408
- "prompt_length": len(prompt),
1409
- "response": summarize_pr_list(payload),
1410
- "result": payload,
1411
- "exit_code": payload.get("exit_code", 0 if payload.get("status") == "ok" else 2),
1412
- }
1413
- return None
1414
-
1415
-
1416
- def dispatch_natural_control_prompt(normalized_prompt: str) -> dict[str, Any] | None:
1417
- return route_natural_control_prompt(ROOT, normalized_prompt)
1418
-
1419
-
1420
- def build_agent_dry_run_plan(prompt: str, args: argparse.Namespace) -> dict[str, Any]:
1421
- normalized = " ".join(prompt.lower().split())
1422
- control_plan = plan_natural_control_prompt(ROOT, normalized)
1423
- if control_plan:
1424
- control_plan["prompt_received"] = True
1425
- control_plan["prompt_length"] = len(prompt)
1426
- return control_plan
1427
- route = route_prompt(prompt)
1428
- execution_plan = build_execution_plan(ROOT, prompt, dry_run=True)
1429
- model_plan = execution_plan.get("model_plan") if isinstance(execution_plan.get("model_plan"), dict) else build_model_plan(prompt, route=route)
1430
- review_gate = execution_plan.get("review_gate") if isinstance(execution_plan.get("review_gate"), dict) else build_review_gate(prompt, route=route, model_plan=model_plan)
1431
- plan: dict[str, Any] = {
1432
- "kind": "agent",
1433
- "status": "planned",
1434
- "ok": True,
1435
- "dry_run": True,
1436
- "requires_llm": False,
1437
- "prompt_received": True,
1438
- "prompt_length": len(prompt),
1439
- "mode": "dry-run",
1440
- "intent": "llm" if not route else route.get("intent"),
1441
- "route": route,
1442
- "llm_backend": getattr(args, "llm", None),
1443
- "external_writes": False,
1444
- "providers": {"used": [], "missing": [], "skipped": []},
1445
- "commands": [],
1446
- "permissions": [],
1447
- "model_plan": model_plan,
1448
- "review_gate": review_gate,
1449
- "execution_plan": execution_plan,
1450
- "orchestration_trace": execution_plan.get("trace", []),
1451
- "response": "Dry-run: nenhuma chamada LLM ou escrita externa foi executada.",
1452
- }
1453
- if "agenda" in normalized:
1454
- plan.update(
1455
- {
1456
- "intent": "calendar",
1457
- "mode": "calendar-dry-run",
1458
- "providers": {"used": ["calendar"], "missing": [], "skipped": []},
1459
- "data_reads": ["configured calendar provider, if present"],
1460
- "response": "Dry-run: o calendario seria consultado localmente se configurado.",
1461
- }
1462
- )
1463
- return plan
1464
- if has_pr_intent(normalized):
1465
- recurring = any(marker in normalized for marker in ("diariamente", "todo dia", "diaria", "diária", "recorrente"))
1466
- plan.update(
1467
- {
1468
- "intent": "github-pr-review",
1469
- "mode": "pr-dry-run",
1470
- "providers": {"used": ["github"], "missing": [], "skipped": []},
1471
- "commands": planned_pr_commands("list-review-requests"),
1472
- "external_writes": False,
1473
- "permissions": [{"agent": "github-pr-reviewer", "provider": "github", "required_level": "read-only"}],
1474
- "response": (
1475
- "Dry-run: a automacao diaria de PR seria planejada em modo report-only."
1476
- if recurring
1477
- else "Dry-run: PRs aguardando revisao seriam listadas via gh em modo report-only."
1478
- ),
1479
- }
1480
- )
1481
- return plan
1482
- if route:
1483
- plan["providers"] = {"used": [route.get("provider")], "missing": [], "skipped": []}
1484
- plan["response"] = "Dry-run: a capability roteada seria executada somente apos validar source/provider."
1485
- return plan
1486
- plan["response"] = "Dry-run: o prompt exigiria LLM configurada; nenhuma chamada foi feita."
1487
- return plan
1488
-
1489
-
1490
- def has_pr_intent(normalized_prompt: str) -> bool:
1491
- tokens = {token.strip(".,;:!?()[]{}\"'") for token in normalized_prompt.split()}
1492
- return bool({"pr", "prs"} & tokens) or "pull request" in normalized_prompt or "pull requests" in normalized_prompt
1493
-
1494
-
1495
- def summarize_pr_list(payload: dict[str, Any]) -> str:
1496
- if payload.get("status") != "ok":
1497
- return str(payload.get("message") or "Nao foi possivel listar PRs.")
1498
- items = payload.get("items") or []
1499
- if not items:
1500
- return "Nenhuma PR aguardando sua revisao foi encontrada."
1501
- lines = []
1502
- for item in items:
1503
- number = item.get("number")
1504
- title = item.get("title") or "-"
1505
- url = item.get("url") or ""
1506
- lines.append(f"- #{number} {title} {url}".strip())
1507
- return "\n".join(lines)
1508
-
1509
-
1510
- def finalize_agent_session(
1511
- result: dict[str, Any],
1512
- session: dict[str, Any],
1513
- prompt: str,
1514
- *,
1515
- backend: str | None = None,
1516
- ) -> dict[str, Any]:
1517
- try:
1518
- result["session"] = record_exchange(str(session["id"]), prompt=prompt, result=result, backend=backend)
1519
- except ValueError as exc:
1520
- raise DevKitError(str(exc)) from exc
1521
- return result
1522
-
1523
-
1524
- def invoke_agentic_route(prompt: str, route: dict[str, Any]) -> dict[str, Any]:
1525
- execution_plan = build_execution_plan(ROOT, prompt, dry_run=False)
1526
- try:
1527
- source = resolve_source(
1528
- provider=route.get("provider"),
1529
- intent=route.get("intent"),
1530
- agent_id=route.get("agent_id"),
1531
- )
1532
- except SourceRegistryError as exc:
1533
- raise DevKitError(str(exc)) from exc
1534
-
1535
- if not source:
1536
- wizard = missing_source_wizard(prompt, route, root=ROOT)
1537
- if execution_plan.get("configuration_tasks"):
1538
- execution_plan["configuration_tasks"][0]["setup_wizard"] = wizard
1539
- execution_plan["status"] = "needs-input"
1540
- execution_plan["trace"] = [
1541
- {"agent_id": "task-orchestrator", "action": "plan", "status": "needs-input"},
1542
- {"agent_id": "provider-configurator", "action": "configure", "status": "waiting-for-user"},
1543
- ]
1544
- payload = {
1545
- "kind": "agent",
1546
- "status": "needs-input",
1547
- "ok": False,
1548
- "requires_source": True,
1549
- "provider": route.get("provider"),
1550
- "source_provider": route.get("provider"),
1551
- "prompt_received": True,
1552
- "prompt_length": len(prompt),
1553
- "route": route,
1554
- "napkin": napkin_context(ROOT, agent_id=route.get("agent_id")),
1555
- "execution_plan": execution_plan,
1556
- "orchestration_trace": execution_plan.get("trace", []),
1557
- "setup_wizard": wizard,
1558
- "next_question": wizard.get("next_question"),
1559
- "message": wizard.get("message"),
1560
- "next_steps": [
1561
- "Responda a pergunta do wizard para autorizar ou negar a configuracao desta fonte.",
1562
- "Se preferir teste local, configure uma source com fixture sem armazenar segredos.",
1563
- "O prompt original sera retomado apos a fonte reutilizavel ser configurada.",
1564
- ],
1565
- "exit_code": 2,
1566
- }
1567
- return persist_setup_wizard_payload(payload, execution_plan=execution_plan, route=route)
1568
-
1569
- execution_plan = attach_source_to_primary_task(execution_plan)
1570
- executed, blocked = execute_plan_tasks(
1571
- execution_plan,
1572
- load_agent=load_agent,
1573
- run_capability=lambda agent, capability_id, capability_args: run_capability(agent, capability_id, capability_args, capture_output=True),
1574
- )
1575
- execution_plan = mark_plan_after_execution(execution_plan, executed, blocked)
1576
- result = (executed[0].get("result") if executed else blocked[0].get("result") if blocked and isinstance(blocked[0].get("result"), dict) else {}) or {}
1577
- response = result.get("stdout") or result.get("error") or ""
1578
- record_usage(prompt, route=route, source_id=str(source["id"]))
1579
- model_plan = execution_plan.get("model_plan") if isinstance(execution_plan.get("model_plan"), dict) else build_model_plan(prompt, route=route)
1580
- review_gate = execution_plan.get("review_gate") if isinstance(execution_plan.get("review_gate"), dict) else build_review_gate(prompt, route=route, model_plan=model_plan)
1581
- review_payload = {
1582
- "kind": "agent",
1583
- "status": execution_plan.get("status") if execution_plan.get("status") != "partial" else result.get("status"),
1584
- "ok": bool(executed) and not blocked,
1585
- "response": response,
1586
- }
1587
- review_result = {
1588
- "kind": "execution-review",
1589
- "agent_id": "execution-reviewer",
1590
- "capability_id": "review-final-output",
1591
- "status": "not-run",
1592
- "ok": False,
1593
- }
1594
- if result.get("ok"):
1595
- review_payload, review_gate, review_result = enforce_execution_review(
1596
- prompt=prompt,
1597
- result=review_payload,
1598
- review_gate=review_gate,
1599
- execution_plan=execution_plan,
1600
- producer_backend="deterministic-capability",
1601
- )
1602
- if review_result.get("ok"):
1603
- execution_plan = mark_review_task(execution_plan, reviewer=str(review_result.get("llm_backend") or "execution-reviewer"))
1604
- elif review_gate.get("status") == "needs-review":
1605
- execution_plan = mark_review_task_needs_review(execution_plan, review_result)
1606
- return {
1607
- "kind": "agent",
1608
- "status": review_payload.get("status"),
1609
- "ok": bool(review_payload.get("ok")),
1610
- "mode": "agentic-route",
1611
- "legacy_mode": "deterministic-route",
1612
- "prompt_received": True,
1613
- "prompt_length": len(prompt),
1614
- "route": route,
1615
- "source": public_source(source),
1616
- "napkin": napkin_context(ROOT, agent_id=route.get("agent_id"), source_id=str(source["id"])),
1617
- "model_plan": model_plan,
1618
- "review_gate": review_gate,
1619
- "review_result": review_result,
1620
- "review_task": execution_plan.get("review_task"),
1621
- "execution_plan": execution_plan,
1622
- "orchestration_trace": execution_plan.get("trace", []),
1623
- "response": review_payload.get("response") or response,
1624
- "result": result,
1625
- "exit_code": review_payload.get("exit_code", result.get("exit_code", 0 if executed and not blocked else 1)),
1626
- }
1627
-
1628
-
1629
- def resolve_capabilities_agent(args: argparse.Namespace) -> str | None:
1630
- if args.agent:
1631
- return args.agent
1632
-
1633
- action_or_agent = args.action_or_agent
1634
- if action_or_agent == "list":
1635
- return args.legacy_agent
1636
-
1637
- # Backward compatibility: `ai-devkit capabilities <agent>`.
1638
- if args.legacy_agent:
1639
- raise DevKitError("unexpected extra argument for capabilities")
1640
- return action_or_agent
1641
-
1642
-
1643
- def runner_timeout_seconds() -> int:
1644
- raw = os.environ.get("AI_DEVKIT_RUN_TIMEOUT", "300")
1645
- return int(raw) if raw.isdigit() and int(raw) > 0 else 300
1646
-
1647
-
1648
- def list_agents() -> list[dict[str, Any]]:
1649
- if not AGENTS_DIR.exists():
1650
- return []
1651
-
1652
- agents = []
1653
- for path in sorted(AGENTS_DIR.iterdir()):
1654
- if not path.is_dir():
1655
- continue
1656
- manifest = path / "agent.yaml"
1657
- if not manifest.exists():
1658
- continue
1659
- data = load_manifest(manifest)
1660
- capabilities = list_capabilities(path)
1661
- agents.append(
1662
- {
1663
- "id": data.get("id", path.name),
1664
- "name": data.get("name", path.name),
1665
- "status": data.get("status"),
1666
- "version": data.get("version"),
1667
- "path": str(path.relative_to(ROOT)),
1668
- "purpose": compact_text(data.get("purpose")),
1669
- "capabilities": len(capabilities),
1670
- }
1671
- )
1672
- return agents
1673
-
1674
-
1675
- def load_agent(agent_id: str) -> dict[str, Any]:
1676
- path = AGENTS_DIR / agent_id
1677
- manifest = path / "agent.yaml"
1678
- if not manifest.exists():
1679
- available = ", ".join(item["id"] for item in list_agents()) or "none"
1680
- raise DevKitError(f"agent not found: {agent_id}. available: {available}")
1681
-
1682
- data = load_manifest(manifest)
1683
- data["path"] = path
1684
- data["manifest_path"] = manifest
1685
- return data
1686
-
1687
-
1688
- def summarize_agent(agent: dict[str, Any]) -> dict[str, Any]:
1689
- return {
1690
- "id": agent.get("id"),
1691
- "name": agent.get("name"),
1692
- "status": agent.get("status"),
1693
- "version": agent.get("version"),
1694
- "path": str(agent["path"].relative_to(ROOT)),
1695
- }
1696
-
1697
-
1698
- def list_all_capabilities() -> list[dict[str, Any]]:
1699
- capabilities: list[dict[str, Any]] = []
1700
- for agent in list_agents():
1701
- agent_path = AGENTS_DIR / agent["id"]
1702
- for capability in list_capabilities(agent_path):
1703
- item = dict(capability)
1704
- item["agent"] = agent["id"]
1705
- capabilities.append(item)
1706
- return capabilities
1707
-
1708
-
1709
- def list_capabilities(agent_path: Path) -> list[dict[str, Any]]:
1710
- capabilities_dir = agent_path / "capabilities"
1711
- if not capabilities_dir.exists():
1712
- return []
1713
-
1714
- capabilities = []
1715
- for path in sorted(capabilities_dir.iterdir()):
1716
- if not path.is_dir():
1717
- continue
1718
- manifest = path / "capability.yaml"
1719
- if not manifest.exists():
1720
- continue
1721
- data = load_manifest(manifest)
1722
- runner = ((data.get("entrypoint", {}) or {}).get("runner"))
1723
- capabilities.append(
1724
- {
1725
- "id": data.get("id", path.name),
1726
- "name": data.get("name", path.name),
1727
- "status": data.get("status"),
1728
- "version": data.get("version"),
1729
- "path": str(path.relative_to(ROOT)),
1730
- "purpose": compact_text(data.get("purpose")),
1731
- "write_policy": data.get("write_policy"),
1732
- "runner": runner,
1733
- "has_runner": bool(runner),
1734
- "has_workflow": (path / "workflow.md").exists(),
1735
- "has_decision_rules": (path / "decision-rules.md").exists(),
1736
- }
1737
- )
1738
- return capabilities
1739
-
1740
-
1741
- def load_capability(agent_path: Path, capability_id: str) -> dict[str, Any]:
1742
- path = agent_path / "capabilities" / capability_id
1743
- manifest = path / "capability.yaml"
1744
- if not manifest.exists():
1745
- available = ", ".join(item["id"].split(".")[-1] for item in list_capabilities(agent_path))
1746
- raise DevKitError(
1747
- f"capability not found: {capability_id}. available: {available or 'none'}"
1748
- )
1749
-
1750
- data = load_manifest(manifest)
1751
- return {
1752
- "id": data.get("id", capability_id),
1753
- "name": data.get("name", capability_id),
1754
- "status": data.get("status"),
1755
- "version": data.get("version"),
1756
- "path": str(path.relative_to(ROOT)),
1757
- "purpose": compact_text(data.get("purpose")),
1758
- "inputs": data.get("inputs", {}),
1759
- "outputs": data.get("outputs", {}),
1760
- "entrypoint": resolve_refs(path, data.get("entrypoint", {})),
1761
- "integration": resolve_integration_refs(path, data.get("integration", {})),
1762
- "write_policy": data.get("write_policy"),
1763
- }
1764
-
1765
-
1766
- def run_capability(
1767
- agent: dict[str, Any],
1768
- capability_id: str,
1769
- capability_args: list[str],
1770
- capture_output: bool = True,
1771
- ) -> dict[str, Any]:
1772
- agent_path = agent["path"]
1773
- capability_path = agent_path / "capabilities" / capability_id
1774
- manifest = capability_path / "capability.yaml"
1775
- if not manifest.exists():
1776
- available = ", ".join(item["id"].split(".")[-1] for item in list_capabilities(agent_path))
1777
- raise DevKitError(
1778
- f"capability not found: {capability_id}. available: {available or 'none'}"
1779
- )
1780
-
1781
- data = load_manifest(manifest)
1782
- try:
1783
- source = None
1784
- if supports_runtime_source(str(agent.get("id")), capability_id):
1785
- source_id, capability_args = extract_source_arg(capability_args)
1786
- source = resolve_source(source_id=source_id) if source_id else None
1787
- capability_args = apply_source_to_args(source, str(agent.get("id")), capability_id, capability_args)
1788
- runtime_env = os.environ | source_env(source)
1789
- except SourceRegistryError as exc:
1790
- return run_payload(
1791
- status="blocked",
1792
- agent=summarize_agent(agent),
1793
- capability=data.get("id", capability_id),
1794
- runner=None,
1795
- returncode=2,
1796
- error=str(exc),
1797
- risks=["Source configuration could not be resolved."],
1798
- next_steps=["Inspect available sources with `agent source list` or configure one with `agent source add`."],
1799
- exit_code=2,
1800
- )
1801
- guardrail = evaluate_execution_guardrails(data, capability_args)
1802
- capability_args = guardrail["args"]
1803
- if not guardrail["ready"]:
1804
- return run_payload(
1805
- status="blocked",
1806
- agent=summarize_agent(agent),
1807
- capability=data.get("id", capability_id),
1808
- runner=None,
1809
- returncode=2,
1810
- guardrail={
1811
- "reason": guardrail["reason"],
1812
- "write_policy": guardrail["write_policy"],
1813
- "execute_requested": True,
1814
- },
1815
- risks=guardrail["risks"],
1816
- next_steps=guardrail["next_steps"],
1817
- exit_code=2,
1818
- )
1819
- readiness = evaluate_provider_requirements(ROOT, data, capability_args)
1820
- if not readiness["ready"]:
1821
- payload = run_payload(
1822
- status=readiness["status"],
1823
- agent=summarize_agent(agent),
1824
- capability=data.get("id", capability_id),
1825
- runner=None,
1826
- returncode=readiness.get("exit_code") or 0,
1827
- providers=readiness["providers"],
1828
- fallback_applied=readiness["fallback_applied"],
1829
- evidence=readiness["evidence"],
1830
- risks=readiness["risks"],
1831
- next_steps=readiness["next_steps"],
1832
- artifacts=readiness["artifacts"],
1833
- exit_code=readiness.get("exit_code"),
1834
- )
1835
- wizard = setup_wizard_from_readiness(readiness, agent=summarize_agent(agent), capability_id=str(data.get("id", capability_id)))
1836
- if wizard:
1837
- payload["setup_wizard"] = wizard
1838
- payload["next_question"] = wizard.get("next_question")
1839
- payload["configuration_agent"] = wizard.get("owner_agent")
1840
- payload["next_steps"] = [
1841
- "Responda a pergunta do wizard para autorizar ou negar a configuracao deste provider.",
1842
- "Informe uma referencia segura de credencial por variavel de ambiente, arquivo ou cadeia nativa quando solicitado.",
1843
- "Reexecute ou retome a mesma capability depois que a configuracao estiver salva.",
1844
- ]
1845
- payload = persist_setup_wizard_payload(payload)
1846
- return payload
1847
-
1848
- runner_ref = (data.get("entrypoint", {}) or {}).get("runner")
1849
- if not runner_ref:
1850
- if capture_output:
1851
- return run_payload(
1852
- status="failed",
1853
- agent=summarize_agent(agent),
1854
- capability=data.get("id", capability_id),
1855
- runner=None,
1856
- returncode=2,
1857
- providers=readiness["providers"],
1858
- error=f"capability has no runner: {capability_id}",
1859
- risks=["Capability cannot be executed by the runtime because no runner is declared."],
1860
- next_steps=["Add `entrypoint.runner` to the capability manifest or use a capability with an executable runner."],
1861
- exit_code=2,
1862
- )
1863
- raise DevKitError(f"capability has no runner: {capability_id}")
1864
-
1865
- runner_path = (capability_path / runner_ref).resolve()
1866
- if not runner_path.exists():
1867
- if capture_output:
1868
- relative_runner = str(runner_path.relative_to(ROOT))
1869
- return run_payload(
1870
- status="failed",
1871
- agent=summarize_agent(agent),
1872
- capability=data.get("id", capability_id),
1873
- runner=relative_runner,
1874
- returncode=2,
1875
- providers=readiness["providers"],
1876
- error=f"runner not found: {relative_runner}",
1877
- risks=["Capability runner declared in the manifest does not exist on disk."],
1878
- next_steps=["Fix `entrypoint.runner` in the capability manifest or restore the missing runner file."],
1879
- exit_code=2,
1880
- )
1881
- raise DevKitError(f"runner not found: {runner_path.relative_to(ROOT)}")
1882
-
1883
- timeout_seconds = runner_timeout_seconds()
1884
- try:
1885
- if capture_output:
1886
- process = subprocess.run(
1887
- [sys.executable, str(runner_path), *capability_args],
1888
- cwd=ROOT,
1889
- check=False,
1890
- text=True,
1891
- stdout=subprocess.PIPE,
1892
- stderr=subprocess.PIPE,
1893
- env=runtime_env,
1894
- timeout=timeout_seconds,
1895
- )
1896
- else:
1897
- process = subprocess.run(
1898
- [sys.executable, str(runner_path), *capability_args],
1899
- cwd=ROOT,
1900
- check=False,
1901
- text=True,
1902
- env=runtime_env,
1903
- timeout=timeout_seconds,
1904
- )
1905
- except subprocess.TimeoutExpired as exc:
1906
- if capture_output:
1907
- stdout = exc.stdout or ""
1908
- stderr = exc.stderr or ""
1909
- if isinstance(stdout, bytes):
1910
- stdout = stdout.decode(errors="replace")
1911
- if isinstance(stderr, bytes):
1912
- stderr = stderr.decode(errors="replace")
1913
- return run_payload(
1914
- status="failed",
1915
- agent=summarize_agent(agent),
1916
- capability=data.get("id", capability_id),
1917
- runner=str(runner_path.relative_to(ROOT)),
1918
- stdout=stdout,
1919
- stderr=stderr,
1920
- returncode=124,
1921
- providers=readiness["providers"],
1922
- error=f"runner timed out after {timeout_seconds}s: {agent.get('id')}/{capability_id}",
1923
- risks=["Capability runner exceeded the configured timeout."],
1924
- next_steps=["Review runner performance, inputs, provider latency, or increase `AI_DEVKIT_RUN_TIMEOUT` for this execution."],
1925
- exit_code=124,
1926
- )
1927
- raise DevKitError(f"runner timed out after {timeout_seconds}s: {agent.get('id')}/{capability_id}") from exc
1928
- if process.returncode != 0:
1929
- stderr = process.stderr if capture_output else ""
1930
- if capture_output:
1931
- stdout = process.stdout or ""
1932
- message = (stderr or stdout or f"runner failed: {process.returncode}").strip()
1933
- return run_payload(
1934
- status="failed",
1935
- agent=summarize_agent(agent),
1936
- capability=data.get("id", capability_id),
1937
- runner=str(runner_path.relative_to(ROOT)),
1938
- stdout=stdout,
1939
- stderr=stderr,
1940
- returncode=process.returncode,
1941
- providers=readiness["providers"],
1942
- error=message,
1943
- risks=["Capability runner returned a non-zero exit code."],
1944
- next_steps=["Review stdout/stderr and rerun after correcting the capability inputs or environment."],
1945
- exit_code=process.returncode,
1946
- )
1947
- raise DevKitError((stderr or "").strip() or f"runner failed: {process.returncode}")
1948
-
1949
- return run_payload(
1950
- status="ok",
1951
- agent=summarize_agent(agent),
1952
- capability=data.get("id", capability_id),
1953
- runner=str(runner_path.relative_to(ROOT)),
1954
- stdout=process.stdout if capture_output else "",
1955
- stderr=process.stderr if capture_output else "",
1956
- returncode=process.returncode,
1957
- providers=readiness["providers"],
1958
- )
1959
-
1960
-
1961
- def supports_runtime_source(agent_id: str, capability_id: str) -> bool:
1962
- return agent_id == "azure-devops-orchestrator" and capability_id == "read-card"
1963
-
1964
-
1965
- def setup_wizard_from_readiness(readiness: dict[str, Any], *, agent: dict[str, Any], capability_id: str) -> dict[str, Any] | None:
1966
- providers = readiness.get("providers") if isinstance(readiness.get("providers"), dict) else {}
1967
- missing = providers.get("missing") or []
1968
- if not missing:
1969
- return None
1970
- provider_id = str(missing[0])
1971
- details = providers.get("details") or []
1972
- detail = next((item for item in details if isinstance(item, dict) and item.get("id") == provider_id), {})
1973
- try:
1974
- return provider_wizard_from_requirement(
1975
- ROOT,
1976
- provider_id,
1977
- agent_id=str(agent.get("id") or ""),
1978
- capability_id=capability_id,
1979
- reason=str(detail.get("purpose") or "Provider is required but not configured."),
1980
- )
1981
- except Exception:
1982
- return None
1983
-
1984
-
1985
- def doctor(project: str | None = None, home: str | None = None, scope: str = "auto") -> dict[str, Any]:
1986
- agents = list_agents()
1987
- capabilities = list_all_capabilities()
1988
- declared_runners = sum(1 for item in capabilities if item.get("has_runner"))
1989
- workflows = sum(1 for item in capabilities if item.get("has_workflow"))
1990
- decision_rules = sum(1 for item in capabilities if item.get("has_decision_rules"))
1991
- validator = ROOT / "scripts" / "validate-repo.py"
1992
- errors: list[str] = []
1993
- warnings: list[str] = []
1994
-
1995
- if not ROOT.exists():
1996
- errors.append(f"root not found: {ROOT}")
1997
- if not AGENTS_DIR.is_dir():
1998
- errors.append(f"agents directory not found: {AGENTS_DIR}")
1999
- if not validator.exists():
2000
- warnings.append("scripts/validate-repo.py not found")
2001
- project_path = doctor_project_path(project, scope)
2002
- home_path = Path(home) if home else None
2003
- locks = lock_status(project_path, home_path)
2004
- if project and locks["status"] == "diverged":
2005
- warnings.append("lock divergence between global runtime.lock and project ai-devkit.lock")
2006
- checks = {
2007
- "root_exists": ROOT.exists(),
2008
- "agents_dir_exists": AGENTS_DIR.is_dir(),
2009
- "validator_exists": validator.exists(),
2010
- "agent_command_exists": (ROOT / "agent").exists(),
2011
- "aikit_command_exists": (ROOT / "aikit").exists(),
2012
- "ai_devkit_command_exists": (ROOT / "ai-devkit").exists(),
2013
- "agent_on_path": shutil.which("agent") is not None,
2014
- }
2015
- diagnostics = build_diagnostics(
2016
- ROOT,
2017
- project=project_path,
2018
- home=home_path,
2019
- runtime_checks=checks,
2020
- runtime_status="ok" if not errors else "error",
2021
- locks=locks,
2022
- )
2023
-
2024
- return {
2025
- "kind": "doctor",
2026
- "status": "ok" if not errors else "error",
2027
- "scope": scope,
2028
- "root": str(ROOT),
2029
- "summary": {
2030
- "agents": len(agents),
2031
- "capabilities": len(capabilities),
2032
- "declared_runners": declared_runners,
2033
- "workflows": workflows,
2034
- "decision_rules": decision_rules,
2035
- },
2036
- "checks": checks,
2037
- "errors": errors,
2038
- "warnings": warnings,
2039
- "locks": locks,
2040
- "diagnostics": diagnostics,
2041
- }
2042
-
2043
-
2044
- def doctor_project_path(project: str | None, scope: str) -> Path | None:
2045
- if project:
2046
- return Path(project)
2047
- if scope == "project":
2048
- return Path.cwd()
2049
- return None
2050
-
2051
-
2052
- def resolve_refs(base: Path, refs: dict[str, Any]) -> dict[str, Any]:
2053
- resolved = {}
2054
- for key, value in refs.items():
2055
- if isinstance(value, str):
2056
- resolved[key] = {
2057
- "ref": value,
2058
- "path": str((base / value).resolve().relative_to(ROOT)),
2059
- "exists": (base / value).resolve().exists(),
2060
- }
2061
- else:
2062
- resolved[key] = value
2063
- return resolved
2064
-
2065
-
2066
- def resolve_integration_refs(base: Path, integration: dict[str, Any]) -> dict[str, Any]:
2067
- if not integration:
2068
- return {}
2069
-
2070
- resolved: dict[str, Any] = {}
2071
- repository = integration.get("repository")
2072
- if repository:
2073
- repository_path = (base / repository).resolve()
2074
- resolved["repository"] = {
2075
- "ref": repository,
2076
- "path": str(repository_path.relative_to(ROOT)),
2077
- "exists": repository_path.exists(),
2078
- }
2079
-
2080
- methods = []
2081
- for method in integration.get("methods", []) or []:
2082
- method_path = (base / method).resolve()
2083
- methods.append(
2084
- {
2085
- "ref": method,
2086
- "path": str(method_path.relative_to(ROOT)),
2087
- "exists": method_path.exists(),
2088
- }
2089
- )
2090
- resolved["methods"] = methods
2091
- return resolved
2092
-
2093
-
2094
- def load_manifest(path: Path) -> dict[str, Any]:
2095
- try:
2096
- import yaml # type: ignore
2097
- except ImportError:
2098
- return load_simple_yaml(path)
2099
-
2100
- with path.open(encoding="utf-8") as file:
2101
- data = yaml.safe_load(file) or {}
2102
- if not isinstance(data, dict):
2103
- raise DevKitError(f"manifest must be a mapping: {path}")
2104
- return data
2105
-
2106
-
2107
- def load_simple_yaml(path: Path) -> dict[str, Any]:
2108
- # Fallback parser for simple top-level YAML used by the CLI when PyYAML is
2109
- # unavailable. It is intentionally narrow; install PyYAML for full support.
2110
- data: dict[str, Any] = {}
2111
- current_key: str | None = None
2112
- current_list: list[str] | None = None
2113
- for raw_line in path.read_text(encoding="utf-8").splitlines():
2114
- line = raw_line.rstrip()
2115
- stripped = line.strip()
2116
- if not stripped or stripped.startswith("#"):
2117
- continue
2118
- if not line.startswith(" ") and ":" in line:
2119
- key, value = line.split(":", 1)
2120
- current_key = key.strip()
2121
- value = value.strip()
2122
- if value:
2123
- data[current_key] = parse_scalar(value)
2124
- current_list = None
2125
- else:
2126
- current_list = []
2127
- data[current_key] = current_list
2128
- continue
2129
- if current_key and current_list is not None and stripped.startswith("- "):
2130
- current_list.append(stripped[2:].strip())
2131
- return data
2132
-
2133
-
2134
- def parse_scalar(value: str) -> Any:
2135
- if value in {"true", "false"}:
2136
- return value == "true"
2137
- return value.strip('"').strip("'")
2138
-
2139
-
2140
- def compact_text(value: Any) -> str | None:
2141
- if value is None:
2142
- return None
2143
- return " ".join(str(value).split())
2144
-
2145
-
2146
- def print_human(result: dict[str, Any]) -> None:
2147
- kind = result["kind"]
2148
- if kind == "version":
2149
- print(f"{result.get('program', 'aikit')} {result['version']}")
2150
- elif kind == "agents":
2151
- print_agents(result["items"])
2152
- elif kind == "capabilities":
2153
- print_capabilities(result["agent"], result["items"])
2154
- elif kind == "capability":
2155
- print_capability(result)
2156
- elif kind == "run":
2157
- print_run(result)
2158
- elif kind == "doctor":
2159
- print_doctor(result)
2160
- elif kind == "commands":
2161
- print_command_modes(result)
2162
- elif kind == "agent":
2163
- print_agent_response(result)
2164
- elif kind == "llm-backends":
2165
- print_llm_backends(result)
2166
- elif kind == "llm-doctor":
2167
- print_llm_doctor(result)
2168
- elif kind == "llm-configure":
2169
- print_llm_configure(result)
2170
- elif kind == "llm-default":
2171
- print_llm_default(result)
2172
- elif kind == "llm-preference":
2173
- print_llm_preference(result)
2174
- elif kind == "providers":
2175
- print_providers(result)
2176
- elif kind == "provider-status":
2177
- print_provider_status(result)
2178
- elif kind == "provider-configure":
2179
- print_provider_configure(result)
2180
- elif kind == "provider-unset":
2181
- print_provider_unset(result)
2182
- elif kind == "credential-resolution":
2183
- print_credential_resolution(result)
2184
- elif kind == "credential-backends":
2185
- print_credential_backends(result)
2186
- elif kind == "sources":
2187
- print_sources(result)
2188
- elif kind == "source-status":
2189
- print_source_status(result)
2190
- elif kind == "source-configure":
2191
- print_source_configure(result)
2192
- elif kind == "source-remove":
2193
- print_source_remove(result)
2194
- elif kind in {"wizards", "wizard"}:
2195
- print_wizard(result)
2196
- elif kind == "memory":
2197
- print_memory(result)
2198
- elif kind == "memory-path":
2199
- print_memory_path(result)
2200
- elif kind == "memory-reset":
2201
- print_memory_reset(result)
2202
- elif kind == "personality":
2203
- print_personality(result)
2204
- elif kind == "aliases":
2205
- print_aliases(result)
2206
- elif kind == "alias":
2207
- print_alias(result)
2208
- elif kind == "sessions":
2209
- print_sessions(result)
2210
- elif kind == "session":
2211
- print_session(result)
2212
- elif kind == "setup":
2213
- print_setup(result)
2214
- elif kind == "toolchain":
2215
- print_toolchain(result)
2216
- elif kind == "toolchain-doctor":
2217
- print_toolchain_doctor(result)
2218
- elif kind == "toolchain-install":
2219
- print_toolchain_install(result)
2220
- elif kind == "tasks":
2221
- print_tasks(result)
2222
- elif kind == "task":
2223
- print_task(result)
2224
- elif kind == "task-history":
2225
- print_task_history(result)
2226
- elif kind == "task-run":
2227
- print_task_run(result)
2228
- elif kind == "scheduler":
2229
- print_scheduler(result)
2230
- elif kind == "calendar":
2231
- print_calendar(result)
2232
- elif kind == "calendar-configure":
2233
- print_calendar_configure(result)
2234
- elif kind in {"pr", "pr-review", "pr-automation"}:
2235
- print_pr(result)
2236
- elif kind == "permissions":
2237
- print_permissions(result)
2238
- elif kind in {"audit", "audit-entry", "audit-export"}:
2239
- print_audit(result)
2240
- elif kind == "config":
2241
- print_config(result)
2242
- elif kind in {"tools", "tool", "integrations", "integration", "skills", "skill", "decisions", "decision", "decisions-reset"}:
2243
- print_control(result)
2244
- elif kind in {"ollama-status", "ollama-models", "ollama-pull", "ollama-update"}:
2245
- print_ollama(result)
2246
- elif kind == "install":
2247
- print_install(result)
2248
- else:
2249
- print(json.dumps(result, ensure_ascii=False, indent=2))
2250
-
2251
-
2252
- def print_agents(items: list[dict[str, Any]]) -> None:
2253
- if not items:
2254
- print("No agents found.")
2255
- return
2256
- for item in items:
2257
- count = item.get("capabilities", 0)
2258
- print(f"{item['id']} {item.get('status') or '-'} {count} capabilities")
2259
- if item.get("purpose"):
2260
- print(f" {item['purpose']}")
2261
-
2262
-
2263
- def print_capabilities(agent: str | None, items: list[dict[str, Any]]) -> None:
2264
- if not items:
2265
- suffix = f" for {agent}" if agent else ""
2266
- print(f"No capabilities found{suffix}.")
2267
- return
2268
- if agent:
2269
- print(f"{agent}:")
2270
- for item in items:
2271
- short_id = item["id"].split(".")[-1]
2272
- prefix = "" if agent else f"{item.get('agent', '-')}/"
2273
- runner = "runner" if item.get("has_runner") else "no-runner"
2274
- workflow = "workflow" if item.get("has_workflow") else "no-workflow"
2275
- rules = "rules" if item.get("has_decision_rules") else "no-rules"
2276
- print(f"- {prefix}{short_id} {item.get('write_policy') or '-'} {item.get('status') or '-'} {runner} {workflow} {rules}")
2277
- if item.get("purpose"):
2278
- print(f" {item['purpose']}")
2279
-
2280
-
2281
- def print_capability(result: dict[str, Any]) -> None:
2282
- agent = result["agent"]
2283
- capability = result["capability"]
2284
- print(f"{agent['id']} / {capability['id'].split('.')[-1]}")
2285
- print(f"Status: {capability.get('status') or '-'}")
2286
- print(f"Version: {capability.get('version') or '-'}")
2287
- print(f"Write policy: {capability.get('write_policy') or '-'}")
2288
- if capability.get("purpose"):
2289
- print(f"\n{capability['purpose']}")
2290
- print("\nEntrypoints:")
2291
- for key, value in capability.get("entrypoint", {}).items():
2292
- if isinstance(value, dict):
2293
- marker = "ok" if value["exists"] else "missing"
2294
- print(f"- {key}: {value['path']} [{marker}]")
2295
- integration = capability.get("integration", {})
2296
- if integration:
2297
- print("\nIntegration:")
2298
- repo = integration.get("repository")
2299
- if repo:
2300
- marker = "ok" if repo["exists"] else "missing"
2301
- print(f"- repository: {repo['path']} [{marker}]")
2302
- for method in integration.get("methods", []):
2303
- marker = "ok" if method["exists"] else "missing"
2304
- print(f"- method: {method['path']} [{marker}]")
2305
-
2306
-
2307
- def print_run(result: dict[str, Any]) -> None:
2308
- if result.get("status") in {None, "ok"}:
2309
- print(result.get("stdout", ""), end="")
2310
- return
2311
-
2312
- print(f"Run {result['status']}: {result['agent']['id']} / {result['capability'].split('.')[-1]}")
2313
- if result.get("fallback_applied"):
2314
- print(f"Fallback: {result['fallback_applied']}")
2315
- providers = result.get("providers") or {}
2316
- missing = providers.get("missing") or []
2317
- if missing:
2318
- print(f"Missing providers: {', '.join(missing)}")
2319
- if result.get("risks"):
2320
- print("\nRisks:")
2321
- for risk in result["risks"]:
2322
- print(f"- {risk}")
2323
- if result.get("next_steps"):
2324
- print("\nNext steps:")
2325
- for step in result["next_steps"]:
2326
- print(f"- {step}")
2327
-
2328
-
2329
- def print_doctor(result: dict[str, Any]) -> None:
2330
- print(f"AI DevKit doctor: {result['status']}")
2331
- print(f"Root: {result['root']}")
2332
- summary = result["summary"]
2333
- print(f"Agents: {summary['agents']}")
2334
- print(f"Capabilities: {summary['capabilities']}")
2335
- print(f"Declared runners: {summary['declared_runners']}")
2336
- print(f"Workflows: {summary['workflows']}")
2337
- print(f"Decision rules: {summary['decision_rules']}")
2338
- diagnostics = result.get("diagnostics") or {}
2339
- if diagnostics:
2340
- providers = diagnostics.get("providers") or {}
2341
- llm = diagnostics.get("llm") or {}
2342
- plugins = diagnostics.get("plugins") or {}
2343
- locks = diagnostics.get("locks") or {}
2344
- print("\nDiagnostics:")
2345
- print(f"- Locks: {locks.get('status', '-')}")
2346
- print(f"- Plugins: {plugins.get('status', '-')}")
2347
- print(f"- Providers: {providers.get('status', '-')} ({providers.get('ok', 0)} ok, {providers.get('missing', 0)} missing)")
2348
- print(f"- LLM: {llm.get('status', '-')} ({llm.get('ok', 0)} ok, {llm.get('missing', 0)} missing)")
2349
- if result["warnings"]:
2350
- print("\nWarnings:")
2351
- for warning in result["warnings"]:
2352
- print(f"- {warning}")
2353
- if result["errors"]:
2354
- print("\nErrors:")
2355
- for error in result["errors"]:
2356
- print(f"- {error}")
2357
-
2358
-
2359
- def print_command_modes(result: dict[str, Any]) -> None:
2360
- print("Deterministic commands (no LLM required):")
2361
- for item in result["deterministic"]:
2362
- print(f"- {item['command']}")
2363
- print("\nLLM commands:")
2364
- for item in result["llm"]:
2365
- print(f"- {item['command']}")
2366
-
2367
-
2368
- def print_agent_response(result: dict[str, Any]) -> None:
2369
- if result.get("status") == "ok":
2370
- print(result.get("response", ""))
2371
- return
2372
- print(result.get("message") or result.get("response") or "Agent execution did not complete.")
2373
- question = result.get("next_question") or ((result.get("setup_wizard") or {}).get("next_question") if isinstance(result.get("setup_wizard"), dict) else None)
2374
- if isinstance(question, dict) and question.get("text"):
2375
- print(f"\nPergunta: {question['text']}")
2376
- if question.get("type") == "confirm":
2377
- print("[s/N]")
2378
- wizard = result.get("setup_wizard") if isinstance(result.get("setup_wizard"), dict) else {}
2379
- if wizard.get("wizard_id"):
2380
- print(f"\nWizard: {wizard['wizard_id']}")
2381
- print(f"Responder: agent wizard answer {wizard['wizard_id']} <resposta>")
2382
- if result.get("llm_backend"):
2383
- print(f"Requested backend: {result['llm_backend']}")
2384
- if result.get("next_steps"):
2385
- print("\nNext steps:")
2386
- for step in result["next_steps"]:
2387
- print(f"- {step}")
2388
-
2389
-
2390
- def print_wizard(result: dict[str, Any]) -> None:
2391
- if result.get("kind") == "wizards":
2392
- items = result.get("items") or []
2393
- print(f"Wizards: {len(items)}")
2394
- for item in items:
2395
- print(f"- {item.get('wizard_id')} {item.get('status')} {item.get('provider')}")
2396
- return
2397
- wizard = result.get("wizard") if isinstance(result.get("wizard"), dict) else result.get("setup_wizard")
2398
- if not isinstance(wizard, dict):
2399
- print(json.dumps(result, ensure_ascii=False, indent=2))
2400
- return
2401
- print(f"Wizard {wizard.get('wizard_id')}: {wizard.get('status')}")
2402
- print(f"Provider: {wizard.get('provider')}")
2403
- question = result.get("next_question") or wizard.get("next_question")
2404
- if isinstance(question, dict) and question.get("text"):
2405
- print(f"Pergunta: {question['text']}")
2406
- if question.get("type") == "confirm":
2407
- print("[s/N]")
2408
- print(f"Responder: agent wizard answer {wizard.get('wizard_id')} <resposta>")
2409
- if result.get("source_result"):
2410
- source = result["source_result"].get("source") or {}
2411
- print(f"Source configurada: {source.get('id')}")
2412
- if result.get("resumed_prompt"):
2413
- resume = result.get("resume_result") or {}
2414
- print(f"Prompt retomado: {resume.get('status')}")
2415
-
2416
-
2417
- def print_sources(result: dict[str, Any]) -> None:
2418
- print(f"Sources config: {result['config_path']}")
2419
- if not result["items"]:
2420
- print("No sources configured.")
2421
- return
2422
- for item in result["items"]:
2423
- print(f"- {item['id']} {item['provider']} {item.get('label') or '-'}")
2424
-
2425
-
2426
- def print_source_status(result: dict[str, Any]) -> None:
2427
- print(f"Source status: {result['status']}")
2428
- for item in result["items"]:
2429
- print(f"- {item['id']}: {item['status']}")
2430
- missing = item.get("missing_env_refs") or []
2431
- if missing:
2432
- print(f" Missing env refs: {', '.join(missing)}")
2433
-
2434
-
2435
- def print_source_configure(result: dict[str, Any]) -> None:
2436
- source = result["source"]
2437
- print(f"Source configured: {source['id']}")
2438
- print(f"Provider: {source['provider']}")
2439
- print(f"Config: {result['config_path']}")
2440
- print("Stored secret: no")
2441
-
2442
-
2443
- def print_source_remove(result: dict[str, Any]) -> None:
2444
- print(f"Source removed: {result['source']['id']}")
2445
- print(f"Config: {result['config_path']}")
2446
-
2447
-
2448
- def print_memory(result: dict[str, Any]) -> None:
2449
- print(f"Memory home: {result['memory_home']}")
2450
- if result.get("files"):
2451
- print("\nFiles:")
2452
- for item in result["files"]:
2453
- print(f"- {item['name']}: {item['path']}")
2454
- for bucket in ("prompts", "routes", "sources"):
2455
- print(f"\n{bucket.title()}:")
2456
- items = result["usage"].get(bucket) or []
2457
- if not items:
2458
- print("- none")
2459
- continue
2460
- for item in items:
2461
- print(f"- {item['key']} ({item.get('count', 0)})")
2462
-
2463
-
2464
- def print_memory_reset(result: dict[str, Any]) -> None:
2465
- print("Memory reset.")
2466
- print(f"Config: {result['config_path']}")
2467
-
2468
-
2469
- def print_memory_path(result: dict[str, Any]) -> None:
2470
- print(f"Memory home: {result['home']}")
2471
- if result.get("created"):
2472
- print("Created:")
2473
- for path in result["created"]:
2474
- print(f"- {path}")
2475
- print("Files:")
2476
- for item in result["files"]:
2477
- print(f"- {item['name']}: {item['path']}")
2478
-
2479
-
2480
- def print_personality(result: dict[str, Any]) -> None:
2481
- print(f"Personality: {result.get('status', 'ok')}")
2482
- print(f"Path: {result['path']}")
2483
- print(f"Agent name: {result.get('agent_name') or '-'}")
2484
- print(f"User name: {result.get('user_name') or '-'}")
2485
- print(f"Language: {result.get('language') or '-'}")
2486
- print(f"Tone: {result.get('tone') or '-'}")
2487
- print(f"Detail level: {result.get('detail_level') or '-'}")
2488
- if result.get("message"):
2489
- print(result["message"])
2490
- if result.get("questions"):
2491
- print("Setup questions:")
2492
- for question in result["questions"]:
2493
- print(f"- {question}")
2494
-
2495
-
2496
- def print_aliases(result: dict[str, Any]) -> None:
2497
- print(f"Aliases config: {result['config_path']}")
2498
- if not result["items"]:
2499
- print("No aliases configured.")
2500
- return
2501
- for item in result["items"]:
2502
- print(f"- {item['name']}: {item['path']}")
2503
-
2504
-
2505
- def print_alias(result: dict[str, Any]) -> None:
2506
- print(f"Alias {result['status']}: {result['name']}")
2507
- if result.get("path"):
2508
- print(f"Path: {result['path']}")
2509
- if result.get("removed_paths"):
2510
- print("Removed:")
2511
- for path in result["removed_paths"]:
2512
- print(f"- {path}")
2513
- print(f"Config: {result['config_path']}")
2514
-
2515
-
2516
- def print_sessions(result: dict[str, Any]) -> None:
2517
- print(f"Sessions home: {result['home']}")
2518
- if result.get("active_session_id"):
2519
- print(f"Active: {result['active_session_id']}")
2520
- if not result["items"]:
2521
- print("No sessions found.")
2522
- return
2523
- for item in result["items"]:
2524
- marker = " active" if item.get("active") else ""
2525
- print(
2526
- f"- {item['id']}{marker} {item.get('title') or '-'} "
2527
- f"{item.get('exchange_count', 0)} exchanges ~{item.get('token_estimate', 0)} tokens"
2528
- )
2529
- if item.get("project"):
2530
- print(f" Project: {item['project']}")
2531
-
2532
-
2533
- def print_session(result: dict[str, Any]) -> None:
2534
- session = result["session"]
2535
- print(f"Session {result['status']}: {session['id']}")
2536
- print(f"Title: {session.get('title') or '-'}")
2537
- print(f"Path: {session.get('path') or '-'}")
2538
- print(f"Project: {session.get('project') or '-'}")
2539
- print(f"Exchanges: {session.get('exchange_count', 0)}")
2540
- print(f"Token estimate: {session.get('token_estimate', 0)}")
2541
-
2542
-
2543
- def print_setup(result: dict[str, Any]) -> None:
2544
- print(f"Setup: {result['status']}")
2545
- print(f"Dry-run: {result.get('dry_run', False)}")
2546
- toolchain = result.get("toolchain") or {}
2547
- print(f"Toolchain: {toolchain.get('status', '-')}")
2548
- missing = (toolchain.get("required_missing") or []) + (toolchain.get("optional_missing") or [])
2549
- if missing:
2550
- print(f"Missing: {', '.join(missing)}")
2551
- if result.get("next_steps"):
2552
- print("Next steps:")
2553
- for step in result["next_steps"]:
2554
- print(f"- {step}")
2555
-
2556
-
2557
- def print_toolchain(result: dict[str, Any]) -> None:
2558
- print(f"Toolchain: {result['status']}")
2559
- print(f"Platform: {result['platform']}")
2560
- for item in result["items"]:
2561
- print(f"- {item['id']} {item['command']} required={item['required']}")
2562
-
2563
-
2564
- def print_toolchain_doctor(result: dict[str, Any]) -> None:
2565
- print(f"Toolchain doctor: {result['status']}")
2566
- print(f"Platform: {result['platform']}")
2567
- for item in result["items"]:
2568
- print(f"- {item['id']}: {item['status']}")
2569
- if item.get("binary"):
2570
- print(f" {item['binary']}")
2571
- if item.get("install"):
2572
- print(f" Install: {item['install']}")
2573
-
2574
-
2575
- def print_toolchain_install(result: dict[str, Any]) -> None:
2576
- print(f"Toolchain install: {result['status']}")
2577
- if result.get("message"):
2578
- print(result["message"])
2579
- for plan in result["plans"]:
2580
- print(f"- {plan['id']}: {plan.get('command') or '-'}")
2581
-
2582
-
2583
- def print_tasks(result: dict[str, Any]) -> None:
2584
- print(f"Tasks: {len(result['items'])}")
2585
- for item in result["items"]:
2586
- print(f"- {item['id']} {item['status']} {item.get('title') or '-'}")
2587
-
2588
-
2589
- def print_task(result: dict[str, Any]) -> None:
2590
- if result.get("message"):
2591
- print(result["message"])
2592
- task = result.get("task") or {}
2593
- if task:
2594
- print(f"Task {result['status']}: {task.get('id')}")
2595
- print(f"Title: {task.get('title') or '-'}")
2596
- print(f"Status: {task.get('status') or '-'}")
2597
-
2598
-
2599
- def print_task_history(result: dict[str, Any]) -> None:
2600
- print(result.get("history") or "No history.")
2601
-
2602
-
2603
- def print_task_run(result: dict[str, Any]) -> None:
2604
- print(f"Task run: {result['status']}")
2605
- if result.get("message"):
2606
- print(result["message"])
2607
-
2608
-
2609
- def print_scheduler(result: dict[str, Any]) -> None:
2610
- print(f"Scheduler: {result['status']}")
2611
- if result.get("message"):
2612
- print(result["message"])
2613
- if "due_count" in result:
2614
- print(f"Due tasks: {result['due_count']}")
2615
-
2616
-
2617
- def print_calendar(result: dict[str, Any]) -> None:
2618
- if result.get("status") != "ok":
2619
- print(result.get("message") or "Calendar is not available.")
2620
- for step in result.get("next_steps") or []:
2621
- print(f"- {step}")
2622
- return
2623
- print(calendar_summary(result))
2624
-
2625
-
2626
- def print_calendar_configure(result: dict[str, Any]) -> None:
2627
- print(f"Calendar configured: {result['provider']}")
2628
- print(f"Source: {result['source_ref']}")
2629
- print("Stored secret: no")
2630
-
2631
-
2632
- def print_pr(result: dict[str, Any]) -> None:
2633
- if result.get("message"):
2634
- print(result["message"])
2635
- if result.get("items") is not None:
2636
- print(summarize_pr_list(result))
2637
- elif result.get("summary"):
2638
- print(result["summary"])
2639
- elif result.get("task"):
2640
- task = result["task"]
2641
- print(f"PR automation {result['status']}: {task.get('id')}")
2642
-
2643
-
2644
- def print_permissions(result: dict[str, Any]) -> None:
2645
- print(f"Permissions: {result['status']}")
2646
- if result.get("default_level"):
2647
- print(f"Default: {result['default_level']}")
2648
- if result.get("grant"):
2649
- grant = result["grant"]
2650
- print(f"Grant: {grant.get('agent')} / {grant.get('provider')} -> {grant.get('level')}")
2651
- if result.get("removed") is not None:
2652
- print(f"Removed: {len(result.get('removed') or [])}")
2653
- grants = result.get("grants")
2654
- if grants is not None:
2655
- if not grants:
2656
- print("No explicit grants.")
2657
- for grant in grants:
2658
- print(f"- {grant.get('agent')} / {grant.get('provider')} -> {grant.get('level')}")
2659
- if result.get("json_path"):
2660
- print(f"Policy: {result['json_path']}")
2661
-
2662
-
2663
- def print_audit(result: dict[str, Any]) -> None:
2664
- if result["kind"] == "audit":
2665
- print(f"Audit home: {result['home']}")
2666
- for item in result.get("items") or []:
2667
- print(f"- {item.get('id')} {item.get('created_at')} {item.get('command')} {item.get('status')}")
2668
- return
2669
- if result["kind"] == "audit-entry":
2670
- entry = result.get("entry") or {}
2671
- print(f"Audit: {entry.get('id')}")
2672
- print(f"Created: {entry.get('created_at')}")
2673
- print(f"Command: {entry.get('command')}")
2674
- print(f"Status: {(entry.get('result') or {}).get('status')}")
2675
- print(f"JSON: {result.get('json_path')}")
2676
- print(f"Markdown: {result.get('markdown_path')}")
2677
- return
2678
- print(result.get("content") or "")
2679
-
2680
-
2681
- def print_llm_backends(result: dict[str, Any]) -> None:
2682
- print(f"LLM config: {result['config_path']}")
2683
- print(f"Default: {result.get('default') or '-'}")
2684
- for item in result["items"]:
2685
- markers = []
2686
- if item.get("configured"):
2687
- markers.append("configured")
2688
- if item.get("default"):
2689
- markers.append("default")
2690
- suffix = f" [{' '.join(markers)}]" if markers else ""
2691
- print(f"- {item['id']} {item['kind']} {item['auth']}{suffix}")
2692
- if item.get("notes"):
2693
- print(f" {item['notes']}")
2694
-
2695
-
2696
- def print_llm_doctor(result: dict[str, Any]) -> None:
2697
- print(f"LLM doctor: {result['status']}")
2698
- print(f"Config: {result['config_path']}")
2699
- print(f"Default: {result.get('default') or '-'}")
2700
- for item in result["items"]:
2701
- print(f"- {item['id']}: {item['status']}")
2702
- if item.get("message"):
2703
- print(f" {item['message']}")
2704
-
2705
-
2706
- def print_llm_configure(result: dict[str, Any]) -> None:
2707
- print(f"LLM backend configured: {result['backend']}")
2708
- print(f"Config: {result['config_path']}")
2709
- print(f"Default: {result.get('default') or '-'}")
2710
- print("Stored secret: no")
2711
-
2712
-
2713
- def print_llm_default(result: dict[str, Any]) -> None:
2714
- print(f"Default LLM backend: {result['default']}")
2715
- print(f"Config: {result['config_path']}")
2716
-
2717
-
2718
- def print_llm_preference(result: dict[str, Any]) -> None:
2719
- print(f"LLM preference: {result.get('status', 'ok')}")
2720
- print(f"Primary: {result.get('primary') or '-'}")
2721
- print(f"Fallback enabled: {result.get('fallback_enabled', True)}")
2722
- print("Order:")
2723
- for backend_id in result.get("order") or []:
2724
- print(f"- {backend_id}")
2725
- print(f"Config: {result['config_path']}")
2726
-
2727
-
2728
- def print_providers(result: dict[str, Any]) -> None:
2729
- if not result["items"]:
2730
- print("No providers found.")
2731
- return
2732
- for item in result["items"]:
2733
- write_marker = "writes" if item.get("writes") else "read"
2734
- print(f"- {item['id']} {item['kind']} {item['status']} {write_marker}")
2735
- if item.get("description"):
2736
- print(f" {item['description']}")
2737
-
2738
-
2739
- def print_provider_status(result: dict[str, Any]) -> None:
2740
- print(f"Provider status: {result['status']}")
2741
- for item in result["items"]:
2742
- print(f"- {item['id']}: {item['status']}")
2743
- if item.get("message"):
2744
- print(f" {item['message']}")
2745
- missing = item.get("missing_required_fields") or []
2746
- if missing:
2747
- print(f" Missing config: {', '.join(missing)}")
2748
- auth = item.get("auth") or {}
2749
- missing_secret_fields = auth.get("missing_secret_fields") or []
2750
- if missing_secret_fields:
2751
- print(f" Missing secret refs: {', '.join(missing_secret_fields)}")
2752
- detected_env_file = item.get("detected_env_file") or []
2753
- if detected_env_file:
2754
- print(f" Detected in env-file: {', '.join(detected_env_file)}")
2755
-
2756
-
2757
- def print_provider_configure(result: dict[str, Any]) -> None:
2758
- print(result.get("message") or f"Provider configuration {result['status']}.")
2759
- print(f"Provider: {result['provider']}")
2760
- if result.get("status") == "configured":
2761
- print(f"Config: {result['config_path']}")
2762
- print("Stored secret: no")
2763
- return
2764
- if result.get("status") == "session-only":
2765
- print("Session-only: yes")
2766
- print("Stored secret: no")
2767
- return
2768
- if result.get("required_config_fields"):
2769
- print("Required config fields:")
2770
- for field in result["required_config_fields"]:
2771
- print(f"- {field}")
2772
- print("Next steps:")
2773
- for step in result["next_steps"]:
2774
- print(f"- {step}")
2775
-
2776
-
2777
- def print_provider_unset(result: dict[str, Any]) -> None:
2778
- print(f"Provider config {result['status']}: {result['provider']}")
2779
- print(f"Config: {result['config_path']}")
2780
-
2781
-
2782
- def print_credential_resolution(result: dict[str, Any]) -> None:
2783
- print(f"Credential resolution for {result['provider']}: {result['status']}")
2784
- if result.get("detected_env"):
2785
- print(f"Detected in env: {', '.join(result['detected_env'])}")
2786
- if result.get("detected_env_file"):
2787
- print(f"Detected in env-file: {', '.join(result['detected_env_file'])}")
2788
- if result.get("missing_required_fields"):
2789
- print(f"Missing required fields: {', '.join(result['missing_required_fields'])}")
2790
- auth = result.get("auth") or {}
2791
- if auth.get("missing_secret_fields"):
2792
- print(f"Missing secret refs: {', '.join(auth['missing_secret_fields'])}")
2793
- print("Secret values returned: no")
2794
-
2795
-
2796
- def print_credential_backends(result: dict[str, Any]) -> None:
2797
- print("Credential resolver backends:")
2798
- for item in result["items"]:
2799
- print(f"- {item}")
2800
-
2801
-
2802
- def print_config(result: dict[str, Any]) -> None:
2803
- print(f"Config: {result.get('path')}")
2804
- if result.get("llm"):
2805
- print(f"Primary LLM: {(result['llm'] or {}).get('primary') or '-'}")
2806
- if result.get("ollama"):
2807
- print(f"Ollama: {(result['ollama'] or {}).get('status')}")
2808
-
2809
-
2810
- def print_control(result: dict[str, Any]) -> None:
2811
- kind = result.get("kind")
2812
- if kind == "decisions-reset":
2813
- print(f"Decisions reset: {result.get('category') or 'all'}")
2814
- print(f"Path: {result.get('path')}")
2815
- return
2816
- if "items" in result:
2817
- print(f"{kind}:")
2818
- for item in result.get("items") or []:
2819
- print(f"- {item.get('category')}:{item.get('id')} {item.get('state')}")
2820
- if not result.get("items"):
2821
- print("- none")
2822
- return
2823
- item = result.get("item") or result
2824
- print(f"{item.get('category') or result.get('category')}:{item.get('id') or result.get('id')} {item.get('state') or result.get('state')}")
2825
-
2826
-
2827
- def print_ollama(result: dict[str, Any]) -> None:
2828
- kind = result.get("kind")
2829
- if kind == "ollama-status":
2830
- print(f"Ollama: {result.get('status')}")
2831
- print(f"Binary: {result.get('binary') or '-'}")
2832
- print(f"Version: {result.get('version') or '-'}")
2833
- daemon = result.get("daemon") or {}
2834
- print(f"Daemon: {daemon.get('status') or '-'}")
2835
- print(f"Models: {result.get('model_count', 0)}")
2836
- if result.get("install_plan"):
2837
- print(f"Install: {(result['install_plan'] or {}).get('command')}")
2838
- return
2839
- if kind == "ollama-models":
2840
- print(f"Ollama models: {result.get('status')}")
2841
- for item in result.get("items") or []:
2842
- print(f"- {item.get('name')} {item.get('size') or '-'}")
2843
- if not result.get("items"):
2844
- print("- none")
2845
- return
2846
- print(f"{kind}: {result.get('status')}")
2847
- if result.get("command"):
2848
- command = result["command"]
2849
- print("Command: " + (" ".join(command) if isinstance(command, list) else str(command)))
2850
- if result.get("message"):
2851
- print(result["message"])
2852
-
2853
-
2854
- def print_install(result: dict[str, Any]) -> None:
2855
- print(f"AI DevKit install: {result['status']}")
2856
- print(f"Scope: {result['scope']}")
2857
- print(f"Target: {result['target']}")
2858
- print(f"Hosts: {', '.join(result['hosts'])}")
2859
- print("Stored secret: no")
2860
- paths = result["planned"] if result.get("dry_run") else result["written"]
2861
- if paths:
2862
- label = "Planned writes" if result.get("dry_run") else "Written files"
2863
- print(f"\n{label}:")
2864
- for path in paths:
2865
- print(f"- {path}")
2866
- if result.get("next_steps"):
2867
- print("\nNext steps:")
2868
- for step in result["next_steps"]:
2869
- print(f"- {step}")
2870
-
2871
-
2872
47
  if __name__ == "__main__":
2873
48
  raise SystemExit(main())