agent-toolkit-cli 1.0.3__py3-none-any.whl

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 (310) hide show
  1. agent_toolkit/__init__.py +4 -0
  2. agent_toolkit/__main__.py +3 -0
  3. agent_toolkit/_paths.py +64 -0
  4. agent_toolkit/cli/__init__.py +0 -0
  5. agent_toolkit/cli/doctor.py +453 -0
  6. agent_toolkit/cli/install.py +445 -0
  7. agent_toolkit/cli/main.py +66 -0
  8. agent_toolkit/cli/mcp.py +418 -0
  9. agent_toolkit/cli/plugin.py +213 -0
  10. agent_toolkit/cli/skills.py +421 -0
  11. agent_toolkit/loop/__init__.py +0 -0
  12. agent_toolkit/loop/gh_gate.py +626 -0
  13. agent_toolkit/loop/runner.py +1548 -0
  14. agent_toolkit/runner/__init__.py +0 -0
  15. agent_toolkit/runner/dispatcher.py +164 -0
  16. agent_toolkit/runner/policy.py +345 -0
  17. agent_toolkit/runner/providers/__init__.py +21 -0
  18. agent_toolkit/runner/providers/anthropic_provider.py +109 -0
  19. agent_toolkit/runner/providers/base.py +53 -0
  20. agent_toolkit/runner/providers/ollama_provider.py +108 -0
  21. agent_toolkit/runner/providers/openai_provider.py +105 -0
  22. agent_toolkit/runner/providers/opencode_provider.py +127 -0
  23. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/architect/AGENT.md +30 -0
  24. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/assistant/AGENT.md +59 -0
  25. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/build-error-resolver/AGENT.md +30 -0
  26. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/client-workflow-bootstrap/AGENT.md +60 -0
  27. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/code-reviewer/AGENT.md +49 -0
  28. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/database-reviewer/AGENT.md +44 -0
  29. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/docs-lookup/AGENT.md +28 -0
  30. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/e2e-runner/AGENT.md +38 -0
  31. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/performance-optimizer/AGENT.md +52 -0
  32. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/planner/AGENT.md +41 -0
  33. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/refactor-cleaner/AGENT.md +43 -0
  34. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/reference-lookup/AGENT.md +33 -0
  35. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/security-reviewer/AGENT.md +47 -0
  36. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/tdd-guide/AGENT.md +58 -0
  37. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/tech-assistant/AGENT.md +11 -0
  38. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/typescript-reviewer/AGENT.md +61 -0
  39. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/catalogs/agent-catalog.yaml +202 -0
  40. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/catalogs/loop-catalog.yaml +165 -0
  41. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/catalogs/skill-catalog.yaml +699 -0
  42. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/catalogs/skills-layout.json +337 -0
  43. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/changelog-drafter/loop.yaml +40 -0
  44. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/ci-sweeper/loop.yaml +53 -0
  45. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/daily-triage/loop.yaml +47 -0
  46. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/dep-sweeper/loop.yaml +46 -0
  47. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/issue-triage/loop.yaml +40 -0
  48. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/oss-daily-briefing/loop.yaml +65 -0
  49. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/oss-pr-monitor/loop.yaml +85 -0
  50. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/oss-triage/loop.yaml +67 -0
  51. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/post-merge-cleanup/loop.yaml +44 -0
  52. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/pr-babysitter/loop.yaml +46 -0
  53. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/clickup/README.md +45 -0
  54. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/clickup/config.template.json +7 -0
  55. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/clickup/wrapper.sh +23 -0
  56. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/figma/README.md +56 -0
  57. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/figma/config.template.json +9 -0
  58. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/github/README.md +11 -0
  59. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/github/config.template.json +7 -0
  60. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/github/wrapper.sh +23 -0
  61. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/linear/README.md +49 -0
  62. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/linear/config.template.json +10 -0
  63. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/notion/README.md +7 -0
  64. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/notion/config.template.json +7 -0
  65. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/notion/wrapper.sh +23 -0
  66. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/slack/README.md +8 -0
  67. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/slack/config.template.json +8 -0
  68. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/slack/wrapper.sh +23 -0
  69. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/CLAUDE.md +66 -0
  70. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/assistant.md +59 -0
  71. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/build-error-resolver.md +30 -0
  72. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/client-workflow-bootstrap.md +60 -0
  73. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/contribution-planner.md +39 -0
  74. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/database-reviewer.md +44 -0
  75. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/docs-lookup.md +28 -0
  76. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/e2e-runner.md +38 -0
  77. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/performance-optimizer.md +52 -0
  78. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/planner.md +41 -0
  79. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/refactor-cleaner.md +43 -0
  80. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/reference-lookup.md +33 -0
  81. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/security-reviewer.md +47 -0
  82. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/tdd-guide.md +58 -0
  83. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/typescript-reviewer.md +61 -0
  84. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/settings.json +87 -0
  85. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/copilot/copilot-instructions.md +15 -0
  86. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/README.md +33 -0
  87. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/architect.mdc +23 -0
  88. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/assistant.mdc +25 -0
  89. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/build-error-resolver.mdc +20 -0
  90. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/code-reviewer.mdc +21 -0
  91. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/database-reviewer.mdc +29 -0
  92. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/docs-lookup.mdc +15 -0
  93. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/e2e-runner.mdc +30 -0
  94. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/performance-optimizer.mdc +27 -0
  95. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/planner.mdc +28 -0
  96. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/refactor-cleaner.mdc +26 -0
  97. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/reference-lookup.mdc +20 -0
  98. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/security-reviewer.mdc +20 -0
  99. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/tdd-guide.mdc +26 -0
  100. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/typescript-reviewer.mdc +28 -0
  101. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/architect.md +30 -0
  102. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/assistant.md +52 -0
  103. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/build-error-resolver.md +31 -0
  104. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/client-workflow-bootstrap.md +66 -0
  105. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/code-reviewer.md +47 -0
  106. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/contribution-planner.md +44 -0
  107. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/database-reviewer.md +43 -0
  108. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/docs-lookup.md +28 -0
  109. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/e2e-runner.md +33 -0
  110. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/performance-optimizer.md +34 -0
  111. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/planner.md +27 -0
  112. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/refactor-cleaner.md +27 -0
  113. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/reference-lookup.md +27 -0
  114. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/security-reviewer.md +27 -0
  115. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/tdd-guide.md +27 -0
  116. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/typescript-reviewer.md +30 -0
  117. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/opencode.json +37 -0
  118. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/pi/skills/architect/skill.md +5 -0
  119. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/pi/skills/assistant/skill.md +3 -0
  120. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/pi/skills/code-reviewer/skill.md +5 -0
  121. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/pi/skills/planner/skill.md +3 -0
  122. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/pi/skills/security-reviewer/skill.md +3 -0
  123. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/memories/global_rules.md +74 -0
  124. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/architect.mdc +23 -0
  125. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/build-error-resolver.mdc +20 -0
  126. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/code-reviewer.mdc +21 -0
  127. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/database-reviewer.mdc +29 -0
  128. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/docs-lookup.mdc +15 -0
  129. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/e2e-runner.mdc +30 -0
  130. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/performance-optimizer.mdc +27 -0
  131. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/planner.mdc +28 -0
  132. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/refactor-cleaner.mdc +26 -0
  133. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/security-reviewer.mdc +20 -0
  134. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/tdd-guide.mdc +26 -0
  135. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/typescript-reviewer.mdc +28 -0
  136. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/assistant/SKILL.md +213 -0
  137. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/assistant/references/AGENTS_TEMPLATE.md +0 -0
  138. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/assistant/references/ORCHESTRATION.md +0 -0
  139. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/assistant/references/REPO_INSPECTION.md +0 -0
  140. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/dev-companion/SKILL.md +65 -0
  141. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/dev-companion/references/LOOP_GUARDRAILS.md +0 -0
  142. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/onboarding/SKILL.md +119 -0
  143. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/output-handshake/SKILL.md +24 -0
  144. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/pr-fallback/SKILL.md +33 -0
  145. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/pr-fallback/references/pr-body-default.md +0 -0
  146. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/workspace-knowledge-sync/SKILL.md +141 -0
  147. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/data/dbt-validation/SKILL.md +41 -0
  148. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/data/snowflake-validation/SKILL.md +38 -0
  149. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/adr/SKILL.md +46 -0
  150. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/adr/references/default-template.md +0 -0
  151. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/adr/references/example-001-graphql-adoption.md +66 -0
  152. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/agreement/SKILL.md +23 -0
  153. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/agreement/references/default-template.md +0 -0
  154. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/agreement/references/example-api-versioning.md +29 -0
  155. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/bug/SKILL.md +25 -0
  156. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/bug/references/default-template.md +0 -0
  157. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/bug/references/example-search-filter-bug.md +58 -0
  158. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/decision-log/SKILL.md +27 -0
  159. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/decision-log/references/default-template.md +0 -0
  160. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/decision-log/references/example-repository-pattern.md +27 -0
  161. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/development-workflow/SKILL.md +33 -0
  162. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/development-workflow/references/default-template.md +0 -0
  163. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/development-workflow/references/default-workflow-checklist.md +44 -0
  164. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/epic/SKILL.md +21 -0
  165. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/epic/references/default-template.md +0 -0
  166. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/epic/references/example-unified-dashboard.md +40 -0
  167. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/incident/SKILL.md +23 -0
  168. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/incident/references/default-template.md +0 -0
  169. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/incident/references/example-payment-outage.md +62 -0
  170. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/management-unit-assessment/SKILL.md +105 -0
  171. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/management-unit-assessment/references/default-template.md +0 -0
  172. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/management-unit-assessment/references/example-team-assessment.md +126 -0
  173. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/meeting-minutes/SKILL.md +24 -0
  174. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/meeting-minutes/references/default-template.md +0 -0
  175. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/meeting-minutes/references/example-weekly-sync.md +72 -0
  176. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/planning/SKILL.md +30 -0
  177. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/planning/references/default-template.md +0 -0
  178. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/planning/references/example-sprint-planning.md +62 -0
  179. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/prd/SKILL.md +44 -0
  180. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/prd/references/default-template.md +0 -0
  181. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/prd/references/example-unified-api.md +71 -0
  182. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/project-assessment/SKILL.md +90 -0
  183. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/project-assessment/references/default-template.md +0 -0
  184. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/project-assessment/references/example-platform-assessment.md +122 -0
  185. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/project-assessment-evidence/SKILL.md +88 -0
  186. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/project-assessment-evidence/references/default-template.md +0 -0
  187. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/project-assessment-evidence/references/example-evidence-map.md +46 -0
  188. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/spike/SKILL.md +23 -0
  189. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/spike/references/default-template.md +0 -0
  190. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/spike/references/example-graphql-federation.md +79 -0
  191. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/task/SKILL.md +20 -0
  192. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/task/references/default-template.md +0 -0
  193. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/task/references/example-nav-system.md +33 -0
  194. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/technical-unit-assessment/SKILL.md +58 -0
  195. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/technical-unit-assessment/references/default-template.md +0 -0
  196. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/technical-unit-assessment/references/example-frontend-assessment.md +112 -0
  197. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/technical-unit-assessment/references/indicator-groups.md +65 -0
  198. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/trd/SKILL.md +47 -0
  199. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/trd/references/default-template.md +0 -0
  200. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/trd/references/example-api-migration.md +122 -0
  201. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/user-story/SKILL.md +20 -0
  202. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/user-story/references/default-template.md +0 -0
  203. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/user-story/references/example-advanced-filtering.md +37 -0
  204. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/work-item/SKILL.md +30 -0
  205. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/work-item/references/default-template.md +0 -0
  206. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/work-item/references/example-routing-dashboard.md +23 -0
  207. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/workflow-client-bootstrap/SKILL.md +148 -0
  208. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/workflow-client-bootstrap/questions.yaml +165 -0
  209. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/workflow-generic-project/SKILL.md +78 -0
  210. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma/LICENSE.txt +2 -0
  211. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma/NOTICE.txt +25 -0
  212. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma/SKILL.md +95 -0
  213. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma/references/figma-mcp-config.md +82 -0
  214. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma/references/figma-tools-and-prompts.md +34 -0
  215. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-code-connect-components/LICENSE.txt +2 -0
  216. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-code-connect-components/NOTICE.txt +18 -0
  217. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-code-connect-components/SKILL.md +350 -0
  218. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-code-connect-components/references/mapping-checklist.md +7 -0
  219. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-code-connect-components/scripts/normalize_node_id.py +25 -0
  220. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-create-design-system-rules/LICENSE.txt +2 -0
  221. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-create-design-system-rules/NOTICE.txt +19 -0
  222. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-create-design-system-rules/SKILL.md +550 -0
  223. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-create-design-system-rules/references/rule-template.md +15 -0
  224. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-create-design-system-rules/scripts/check_agents_md.sh +9 -0
  225. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-create-new-file/LICENSE.txt +2 -0
  226. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-create-new-file/NOTICE.txt +17 -0
  227. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-create-new-file/SKILL.md +69 -0
  228. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-implement-design/LICENSE.txt +2 -0
  229. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-implement-design/NOTICE.txt +19 -0
  230. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-implement-design/SKILL.md +264 -0
  231. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/SKILL.md +60 -0
  232. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/charts.csv +26 -0
  233. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/colors.csv +97 -0
  234. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/icons.csv +101 -0
  235. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/landing.csv +31 -0
  236. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/products.csv +97 -0
  237. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/react-performance.csv +45 -0
  238. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  239. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  240. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  241. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  242. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  243. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  244. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  245. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  246. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/react.csv +54 -0
  247. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  248. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  249. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  250. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  251. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/styles.csv +68 -0
  252. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/typography.csv +58 -0
  253. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  254. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  255. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/web-interface.csv +31 -0
  256. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/references/pre-delivery-checklist.md +39 -0
  257. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/references/search-reference.md +44 -0
  258. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/references/ui-rules.md +35 -0
  259. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/scripts/core.py +253 -0
  260. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/scripts/design_system.py +1067 -0
  261. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/scripts/search.py +114 -0
  262. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-address-comments/LICENSE.txt +202 -0
  263. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-address-comments/NOTICE.txt +20 -0
  264. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-address-comments/SKILL.md +69 -0
  265. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-address-comments/scripts/fetch_comments.py +237 -0
  266. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-contribution-planner/SKILL.md +157 -0
  267. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-contribution-planner/scripts/inspect_contributions.py +800 -0
  268. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-fix-ci/LICENSE.txt +201 -0
  269. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-fix-ci/NOTICE.txt +20 -0
  270. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-fix-ci/SKILL.md +71 -0
  271. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-fix-ci/scripts/inspect_pr_checks.py +509 -0
  272. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/github-cli-workflow/SKILL.md +49 -0
  273. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gitlab-cli-workflow/SKILL.md +44 -0
  274. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/workflow-client-bootstrap/SKILL.md +14 -0
  275. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/workflow-generic-project/SKILL.md +14 -0
  276. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/clickup-cli/SKILL.md +75 -0
  277. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/clickup-cli/references/docs-management.md +57 -0
  278. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/clickup-cli/references/task-management.md +131 -0
  279. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/clickup-cli/references/time-tracking.md +38 -0
  280. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/linear/LICENSE.txt +202 -0
  281. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/linear/NOTICE.txt +23 -0
  282. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/linear/SKILL.md +131 -0
  283. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/slack-assistant/SKILL.md +134 -0
  284. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/slack-cli/SKILL.md +105 -0
  285. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/slack-cli/references/INSTALLATION.md +42 -0
  286. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/loops/loop-runner/SKILL.md +90 -0
  287. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/ops/docs-generator/SKILL.md +81 -0
  288. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/ops/llm-cost-advisor/SKILL.md +83 -0
  289. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/ops/triage/SKILL.md +117 -0
  290. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/LICENSE.txt +201 -0
  291. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/NOTICE.txt +27 -0
  292. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/SKILL.md +142 -0
  293. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/assets/experiment-template.ipynb +110 -0
  294. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/assets/tutorial-template.ipynb +107 -0
  295. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/references/experiment-patterns.md +10 -0
  296. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/references/notebook-structure.md +17 -0
  297. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/references/quality-checklist.md +11 -0
  298. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/references/tutorial-patterns.md +9 -0
  299. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/scripts/new_notebook.py +130 -0
  300. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/playwright-cli/LICENSE.txt +201 -0
  301. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/playwright-cli/NOTICE.txt +29 -0
  302. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/playwright-cli/SKILL.md +151 -0
  303. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/playwright-cli/references/cli.md +116 -0
  304. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/playwright-cli/references/workflows.md +98 -0
  305. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/playwright-cli/scripts/executable_playwright_cli.sh +25 -0
  306. agent_toolkit_cli-1.0.3.dist-info/METADATA +411 -0
  307. agent_toolkit_cli-1.0.3.dist-info/RECORD +310 -0
  308. agent_toolkit_cli-1.0.3.dist-info/WHEEL +4 -0
  309. agent_toolkit_cli-1.0.3.dist-info/entry_points.txt +2 -0
  310. agent_toolkit_cli-1.0.3.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,626 @@
1
+ #!/usr/bin/env python3
2
+ # /// script
3
+ # requires-python = ">=3.10"
4
+ # dependencies = []
5
+ # ///
6
+ """
7
+ bin/loop-gh-gate — Hard autonomy gate for `gh` during loop runs.
8
+
9
+ Installed on PATH as a `gh` shim while a loop runner is active. Intercepts
10
+ mutating GitHub CLI commands and enforces LOOP.md allowlist / deny / tier
11
+ rules. Merge and close additionally require a verifier receipt under the
12
+ active run directory.
13
+
14
+ Environment (set by bin/loop):
15
+ LOOP_GATE_REAL_GH Absolute path to the real `gh` binary
16
+ LOOP_GATE_RUN_DIR Active run artifacts directory
17
+ LOOP_GATE_TIER L1 | L2 | L3
18
+ LOOP_GATE_ALLOWLIST Comma-separated allowlisted actions
19
+ LOOP_GATE_DENY Comma-separated denied actions
20
+ LOOP_GATE_VERIFIER Verifier skill/agent name (optional)
21
+ LOOP_GATE_RECEIPT_SECRET If set, verifier receipts must carry a matching HMAC
22
+ LOOP_GATE_DISABLED If "1", pass through without checks (tests only)
23
+
24
+ Usage (normally via shim):
25
+ loop-gh-gate -- pr merge 123 --repo owner/repo --squash
26
+ loop-gh-gate --classify pr merge 123 --repo owner/repo
27
+ loop-gh-gate --check-receipt merge --repo owner/repo --number 123
28
+ """
29
+ from __future__ import annotations
30
+
31
+ import hashlib
32
+ import hmac
33
+ import json
34
+ import os
35
+ import re
36
+ import subprocess
37
+ import sys
38
+ from datetime import datetime, timezone
39
+ from pathlib import Path
40
+ from typing import Any
41
+
42
+
43
+ # Actions that mutate GitHub state and must be gated.
44
+ MUTATING_ACTIONS = frozenset({
45
+ "merge",
46
+ "close",
47
+ "comment",
48
+ "label",
49
+ "assign",
50
+ "approve",
51
+ "push",
52
+ "commit",
53
+ "force-push",
54
+ "delete",
55
+ })
56
+
57
+ # Merge/close always need a verifier receipt at L2+ (and are denied at L1).
58
+ RECEIPT_REQUIRED = frozenset({"merge", "close"})
59
+
60
+ # Max age for a verifier receipt (seconds).
61
+ RECEIPT_MAX_AGE_SEC = 3600
62
+
63
+
64
+ def _split_csv(value: str | None) -> list[str]:
65
+ if not value:
66
+ return []
67
+ return [p.strip() for p in value.split(",") if p.strip()]
68
+
69
+
70
+ def gate_config_from_env() -> dict[str, Any]:
71
+ return {
72
+ "real_gh": os.environ.get("LOOP_GATE_REAL_GH", ""),
73
+ "run_dir": Path(os.environ["LOOP_GATE_RUN_DIR"]) if os.environ.get("LOOP_GATE_RUN_DIR") else None,
74
+ "tier": (os.environ.get("LOOP_GATE_TIER") or "L1").upper(),
75
+ "allowlist": _split_csv(os.environ.get("LOOP_GATE_ALLOWLIST")),
76
+ "deny": _split_csv(os.environ.get("LOOP_GATE_DENY")),
77
+ "verifier": os.environ.get("LOOP_GATE_VERIFIER") or "",
78
+ "receipt_secret": os.environ.get("LOOP_GATE_RECEIPT_SECRET") or "",
79
+ "disabled": os.environ.get("LOOP_GATE_DISABLED") == "1",
80
+ }
81
+
82
+
83
+ _SENSITIVE_FLAGS = frozenset({
84
+ "-H", "--header", "-b", "--body", "--body-file", "-F", "-f",
85
+ "--raw-field", "--field", "--input", "-i", "--jq",
86
+ })
87
+
88
+
89
+ def redact_argv(argv: list[str]) -> list[str]:
90
+ """Return argv with secret-bearing values replaced by <redacted>."""
91
+ out: list[str] = []
92
+ skip_next = False
93
+ for a in argv:
94
+ if skip_next:
95
+ out.append("<redacted>")
96
+ skip_next = False
97
+ continue
98
+ if a in _SENSITIVE_FLAGS:
99
+ out.append(a)
100
+ skip_next = True
101
+ continue
102
+ if "=" in a and a.startswith("-"):
103
+ flag, _, _val = a.partition("=")
104
+ # Redact inline sensitive values (Authorization headers, body=, etc.)
105
+ low = flag.lower()
106
+ if any(s in low for s in ("header", "body", "field", "input", "token", "auth")):
107
+ out.append(f"{flag}=<redacted>")
108
+ continue
109
+ out.append(a)
110
+ return out
111
+
112
+
113
+ def classify_gh_argv(argv: list[str]) -> tuple[str | None, dict[str, Any]]:
114
+ """Classify a `gh` argv into an action + metadata.
115
+
116
+ Returns (action_or_None_if_readonly, meta).
117
+ Unknown mutating forms return a gated action (typically ``push``) rather
118
+ than falling through as read-only.
119
+ """
120
+ args = [a for a in argv if a != "--"]
121
+ meta: dict[str, Any] = {"repo": None, "number": None, "raw": list(args)}
122
+
123
+ if not args:
124
+ return None, meta
125
+
126
+ # Collect --repo / -R anywhere in argv (gh accepts them mid-command).
127
+ i = 0
128
+ while i < len(args):
129
+ a = args[i]
130
+ if a in ("-R", "--repo") and i + 1 < len(args):
131
+ meta["repo"] = args[i + 1]
132
+ i += 2
133
+ continue
134
+ if a.startswith("--repo="):
135
+ meta["repo"] = a.split("=", 1)[1]
136
+ i += 1
137
+ continue
138
+ i += 1
139
+
140
+ # Strip leading global flags for subcommand detection.
141
+ i = 0
142
+ while i < len(args):
143
+ a = args[i]
144
+ if a in ("-R", "--repo") and i + 1 < len(args):
145
+ i += 2
146
+ continue
147
+ if a.startswith("--repo="):
148
+ i += 1
149
+ continue
150
+ break
151
+
152
+ rest = args[i:]
153
+ if not rest:
154
+ return None, meta
155
+
156
+ # gh pr ...
157
+ if rest[0] == "pr" and len(rest) >= 2:
158
+ sub = rest[1]
159
+ if len(rest) >= 3 and rest[2].isdigit():
160
+ meta["number"] = int(rest[2])
161
+ if sub == "merge":
162
+ return "merge", meta
163
+ if sub == "close":
164
+ return "close", meta
165
+ if sub == "comment":
166
+ return "comment", meta
167
+ if sub == "create":
168
+ return "push", meta # opening a PR is a write
169
+ if sub == "review":
170
+ joined = " ".join(rest)
171
+ if "--approve" in rest or " --approve" in f" {joined}":
172
+ return "approve", meta
173
+ return "comment", meta # request-changes / comment reviews
174
+ if sub == "edit":
175
+ if "--add-label" in rest or "--remove-label" in rest:
176
+ return "label", meta
177
+ if "--add-assignee" in rest or "--remove-assignee" in rest:
178
+ return "assign", meta
179
+ # title/body/base/state edits are mutating but not label/assign
180
+ if any(
181
+ f in rest or any(a.startswith(f"{f}=") for a in rest)
182
+ for f in ("--title", "--body", "--body-file", "--base", "--state")
183
+ ):
184
+ return "push", meta
185
+ return "push", meta # unknown pr edit → deny by default (fail closed)
186
+ if sub in ("ready", "reopen", "lock", "unlock", "delete"):
187
+ return "push" if sub != "delete" else "delete", meta
188
+ if sub in ("list", "view", "status", "diff", "checks"):
189
+ return None, meta
190
+ return "push", meta # unknown pr subcommand → treat as mutating
191
+
192
+ # gh issue ...
193
+ if rest[0] == "issue" and len(rest) >= 2:
194
+ sub = rest[1]
195
+ if len(rest) >= 3 and rest[2].isdigit():
196
+ meta["number"] = int(rest[2])
197
+ if sub == "comment":
198
+ return "comment", meta
199
+ if sub == "create":
200
+ if "--label" in rest or "-l" in rest:
201
+ return "label", meta
202
+ return "push", meta
203
+ if sub == "edit":
204
+ if "--add-assignee" in rest or "--remove-assignee" in rest:
205
+ return "assign", meta
206
+ if "--add-label" in rest or "--remove-label" in rest:
207
+ return "label", meta
208
+ # --state closed / --state open
209
+ for i, a in enumerate(rest):
210
+ if a == "--state" and i + 1 < len(rest) and rest[i + 1] == "closed":
211
+ return "close", meta
212
+ if a.startswith("--state=") and a.split("=", 1)[1] == "closed":
213
+ return "close", meta
214
+ if any(
215
+ f in rest or any(a.startswith(f"{f}=") for a in rest)
216
+ for f in ("--title", "--body", "--body-file")
217
+ ):
218
+ return "push", meta
219
+ return "push", meta
220
+ if sub in ("close",):
221
+ return "close", meta
222
+ if sub in ("list", "view", "status"):
223
+ return None, meta
224
+ return "push", meta
225
+
226
+ # gh api ...
227
+ if rest[0] == "api":
228
+ method = "GET"
229
+ method_explicit = False
230
+ path = ""
231
+ has_field = False
232
+ skip_next = False
233
+ for a in rest[1:]:
234
+ if skip_next:
235
+ skip_next = False
236
+ continue
237
+ if a in ("-X", "--method"):
238
+ skip_next = True
239
+ continue
240
+ if a.startswith("--method="):
241
+ method = a.split("=", 1)[1].upper()
242
+ method_explicit = True
243
+ continue
244
+ if a.startswith("-"):
245
+ if a in ("-F", "-f", "--field", "--raw-field", "-H", "--header", "--input", "-i"):
246
+ if a in ("-F", "-f", "--field", "--raw-field"):
247
+ has_field = True
248
+ skip_next = True
249
+ elif a.startswith(("-F", "-f")) and "=" in a:
250
+ has_field = True
251
+ continue
252
+ if not path:
253
+ path = a
254
+ # Re-scan for method if -X was used
255
+ for i, a in enumerate(rest[1:], 1):
256
+ if a in ("-X", "--method") and i + 1 < len(rest):
257
+ method = rest[i + 1].upper()
258
+ method_explicit = True
259
+ elif a.startswith("--method="):
260
+ method = a.split("=", 1)[1].upper()
261
+ method_explicit = True
262
+ # gh api switches to POST when -f/-F are present unless method is set.
263
+ if has_field and not method_explicit:
264
+ method = "POST"
265
+ if method in ("POST", "PUT", "PATCH", "DELETE"):
266
+ if "/merge" in path:
267
+ return "merge", meta
268
+ if "/comments" in path:
269
+ return "comment", meta
270
+ if "/assignees" in path or "assignees" in path:
271
+ return "assign", meta
272
+ if "/labels" in path:
273
+ return "label", meta
274
+ if re.search(r"/pulls/\d+$", path) and method == "PATCH":
275
+ return "close", meta
276
+ if re.search(r"/issues/\d+$", path) and method == "PATCH":
277
+ # Could be close or assign; treat as push unless assignees/labels
278
+ return "push", meta
279
+ if method == "DELETE":
280
+ return "delete", meta
281
+ return "push", meta # unknown mutating API → typically denied
282
+ return None, meta
283
+
284
+ # Other top-level mutating commands
285
+ if rest[0] in ("release", "gist", "repo", "secret", "variable", "workflow"):
286
+ if len(rest) >= 2 and rest[1] in ("list", "view", "status", "get"):
287
+ return None, meta
288
+ return "push", meta
289
+
290
+ return None, meta
291
+
292
+
293
+ def tier_forbids(tier: str, action: str) -> str | None:
294
+ """Return a reason if the tier itself forbids the action."""
295
+ t = tier.upper()
296
+ if t.startswith("L1") or t == "1":
297
+ return f"L1 report-only forbids '{action}'"
298
+ if (t.startswith("L2") or t == "2") and action in ("merge", "close", "approve", "push", "commit", "force-push", "delete"):
299
+ return f"L2 assisted forbids '{action}' (allow comment/label/assign only)"
300
+ return None
301
+
302
+
303
+ def evaluate_action(
304
+ action: str,
305
+ *,
306
+ tier: str,
307
+ allowlist: list[str],
308
+ deny: list[str],
309
+ ) -> tuple[bool, str]:
310
+ """Return (allowed, reason)."""
311
+ if action not in MUTATING_ACTIONS:
312
+ return True, "non-mutating"
313
+
314
+ reason = tier_forbids(tier, action)
315
+ if reason:
316
+ return False, reason
317
+
318
+ if action in deny:
319
+ return False, f"action '{action}' is on deny list"
320
+
321
+ if action not in allowlist:
322
+ return False, f"action '{action}' is not on allowlist"
323
+
324
+ return True, "allowlisted"
325
+
326
+
327
+ def receipts_dir(run_dir: Path) -> Path:
328
+ d = run_dir / "verifier-receipts"
329
+ d.mkdir(parents=True, exist_ok=True)
330
+ return d
331
+
332
+
333
+ def write_denial(run_dir: Path | None, record: dict[str, Any]) -> None:
334
+ if run_dir is None:
335
+ return
336
+ path = run_dir / "gate-denials.jsonl"
337
+ if "argv" in record:
338
+ record = {**record, "argv": redact_argv(list(record["argv"]))}
339
+ record = {**record, "ts": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")}
340
+ with path.open("a", encoding="utf-8") as fh:
341
+ fh.write(json.dumps(record) + "\n")
342
+
343
+
344
+ def receipt_canonical_payload(data: dict[str, Any]) -> str:
345
+ """Stable JSON payload used for HMAC (excludes `sig`)."""
346
+ payload = {
347
+ "action": data.get("action"),
348
+ "repo": data.get("repo"),
349
+ "number": data.get("number"),
350
+ "approved": bool(data.get("approved")),
351
+ "verifier": data.get("verifier"),
352
+ "rationale": data.get("rationale"),
353
+ "ts": data.get("ts"),
354
+ }
355
+ return json.dumps(payload, sort_keys=True, separators=(",", ":"), ensure_ascii=False)
356
+
357
+
358
+ def sign_receipt(data: dict[str, Any], secret: str) -> str:
359
+ digest = hmac.new(
360
+ secret.encode("utf-8"),
361
+ receipt_canonical_payload(data).encode("utf-8"),
362
+ hashlib.sha256,
363
+ ).hexdigest()
364
+ return digest
365
+
366
+
367
+ def verify_receipt_signature(data: dict[str, Any], secret: str) -> bool:
368
+ expected = data.get("sig")
369
+ if not expected or not isinstance(expected, str):
370
+ return False
371
+ actual = sign_receipt(data, secret)
372
+ return hmac.compare_digest(actual, expected)
373
+
374
+
375
+ def find_verifier_receipt(
376
+ run_dir: Path,
377
+ action: str,
378
+ *,
379
+ repo: str | None = None,
380
+ number: int | None = None,
381
+ verifier: str = "",
382
+ receipt_secret: str = "",
383
+ max_age_sec: int = RECEIPT_MAX_AGE_SEC,
384
+ ) -> dict[str, Any] | None:
385
+ """Find a matching approved receipt for this action/target."""
386
+ d = receipts_dir(run_dir)
387
+ now = datetime.now(timezone.utc)
388
+ candidates: list[tuple[datetime, Path, dict[str, Any]]] = []
389
+
390
+ for path in sorted(d.glob("*.json")):
391
+ try:
392
+ data = json.loads(path.read_text(encoding="utf-8"))
393
+ except (OSError, json.JSONDecodeError):
394
+ continue
395
+ if data.get("action") != action:
396
+ continue
397
+ if not data.get("approved"):
398
+ continue
399
+ # Exact binding when the command targets a specific repo/number.
400
+ if number is not None and data.get("number") != number:
401
+ continue
402
+ if repo is not None and data.get("repo") != repo:
403
+ continue
404
+ if verifier and data.get("verifier") != verifier:
405
+ continue
406
+ ts_raw = data.get("ts") or ""
407
+ try:
408
+ ts = datetime.fromisoformat(str(ts_raw).replace("Z", "+00:00"))
409
+ except ValueError:
410
+ continue
411
+ if ts.tzinfo is None:
412
+ continue
413
+ if (now - ts).total_seconds() > max_age_sec or (now - ts).total_seconds() < -60:
414
+ continue
415
+ if receipt_secret and not verify_receipt_signature(data, receipt_secret):
416
+ continue
417
+ candidates.append((ts, path, data))
418
+
419
+ if not candidates:
420
+ return None
421
+ # Prefer newest when multiple match.
422
+ candidates.sort(key=lambda item: item[0].timestamp(), reverse=True)
423
+ return candidates[0][2]
424
+
425
+
426
+ def require_receipt(
427
+ run_dir: Path,
428
+ action: str,
429
+ *,
430
+ repo: str | None,
431
+ number: int | None,
432
+ verifier: str,
433
+ receipt_secret: str = "",
434
+ ) -> tuple[bool, str]:
435
+ if action not in RECEIPT_REQUIRED:
436
+ return True, "receipt not required"
437
+ if repo is None or number is None:
438
+ return False, f"merge/close require --repo and PR/issue number for receipt binding"
439
+ receipt = find_verifier_receipt(
440
+ run_dir,
441
+ action,
442
+ repo=repo,
443
+ number=number,
444
+ verifier=verifier,
445
+ receipt_secret=receipt_secret,
446
+ )
447
+ if receipt is None:
448
+ sig_hint = ', "sig":"<hmac-sha256>"' if receipt_secret else ""
449
+ return (
450
+ False,
451
+ f"missing verifier receipt for {action} {repo}#{number}"
452
+ + f" — write {run_dir / 'verifier-receipts'}/<id>.json "
453
+ f'{{"action":"{action}","repo":"{repo}","number":{number},'
454
+ f'"approved":true,"verifier":"{verifier or "configured-verifier"}",'
455
+ f'"rationale":"...","ts":"<ISO8601>Z"{sig_hint}}}',
456
+ )
457
+ return True, "receipt ok"
458
+
459
+
460
+ def check_command(
461
+ argv: list[str],
462
+ cfg: dict[str, Any] | None = None,
463
+ ) -> tuple[bool, str, str | None, dict[str, Any]]:
464
+ """Full check. Returns (ok, reason, action, meta)."""
465
+ cfg = cfg or gate_config_from_env()
466
+ if cfg.get("disabled"):
467
+ return True, "gate disabled", None, {}
468
+
469
+ action, meta = classify_gh_argv(argv)
470
+ if action is None:
471
+ return True, "readonly / ungated", None, meta
472
+
473
+ ok, reason = evaluate_action(
474
+ action,
475
+ tier=str(cfg.get("tier") or "L1"),
476
+ allowlist=list(cfg.get("allowlist") or []),
477
+ deny=list(cfg.get("deny") or []),
478
+ )
479
+ if not ok:
480
+ return False, reason, action, meta
481
+
482
+ run_dir = cfg.get("run_dir")
483
+ if action in RECEIPT_REQUIRED:
484
+ if run_dir is None:
485
+ return False, "LOOP_GATE_RUN_DIR not set (cannot verify receipt)", action, meta
486
+ ok_r, reason_r = require_receipt(
487
+ Path(run_dir),
488
+ action,
489
+ repo=meta.get("repo"),
490
+ number=meta.get("number"),
491
+ verifier=str(cfg.get("verifier") or ""),
492
+ receipt_secret=str(cfg.get("receipt_secret") or ""),
493
+ )
494
+ if not ok_r:
495
+ return False, reason_r, action, meta
496
+
497
+ return True, reason, action, meta
498
+
499
+
500
+ def install_gh_shim(
501
+ run_dir: Path,
502
+ *,
503
+ tier: str,
504
+ allowlist: list[str],
505
+ deny: list[str],
506
+ verifier: str = "",
507
+ gate_script: Path | None = None,
508
+ real_gh: str | None = None,
509
+ ) -> dict[str, str]:
510
+ """Create a PATH-first `gh` shim and return env vars for the runner."""
511
+ real = real_gh or shutil_which_gh()
512
+ if not real:
513
+ raise RuntimeError("real `gh` binary not found on PATH")
514
+
515
+ gate_script = gate_script or Path(__file__).resolve()
516
+ shim_dir = run_dir / ".gate" / "bin"
517
+ shim_dir.mkdir(parents=True, exist_ok=True)
518
+ receipts_dir(run_dir)
519
+
520
+ shim = shim_dir / "gh"
521
+ shim.write_text(
522
+ "#!/usr/bin/env bash\n"
523
+ "set -euo pipefail\n"
524
+ f'exec "{sys.executable}" "{gate_script}" -- "$@"\n',
525
+ encoding="utf-8",
526
+ )
527
+ shim.chmod(0o755)
528
+
529
+ env = os.environ.copy()
530
+ env["PATH"] = f"{shim_dir}{os.pathsep}{env.get('PATH', '')}"
531
+ env["LOOP_GATE_REAL_GH"] = real
532
+ env["LOOP_GATE_RUN_DIR"] = str(run_dir)
533
+ env["LOOP_GATE_TIER"] = tier
534
+ env["LOOP_GATE_ALLOWLIST"] = ",".join(allowlist)
535
+ env["LOOP_GATE_DENY"] = ",".join(deny)
536
+ env["LOOP_GATE_VERIFIER"] = verifier
537
+ # Preserve receipt secret from the parent environment when present.
538
+ if os.environ.get("LOOP_GATE_RECEIPT_SECRET"):
539
+ env["LOOP_GATE_RECEIPT_SECRET"] = os.environ["LOOP_GATE_RECEIPT_SECRET"]
540
+ env.pop("LOOP_GATE_DISABLED", None)
541
+ return env
542
+
543
+
544
+ def shutil_which_gh() -> str | None:
545
+ import shutil
546
+ # Prefer a real gh that is NOT our shim (avoid recursion if already gated).
547
+ path = os.environ.get("PATH", "")
548
+ for directory in path.split(os.pathsep):
549
+ candidate = Path(directory) / "gh"
550
+ if candidate.is_file() and os.access(candidate, os.X_OK):
551
+ # Skip if it is our shim (calls loop-gh-gate).
552
+ try:
553
+ text = candidate.read_text(encoding="utf-8", errors="ignore")
554
+ except OSError:
555
+ text = ""
556
+ if "loop-gh-gate" in text or "loop_gh_gate" in text:
557
+ continue
558
+ return str(candidate)
559
+ found = shutil.which("gh")
560
+ return found
561
+
562
+
563
+ def main(argv: list[str] | None = None) -> int:
564
+ argv = list(sys.argv[1:] if argv is None else argv)
565
+
566
+ if argv and argv[0] == "--classify":
567
+ action, meta = classify_gh_argv(argv[1:])
568
+ print(json.dumps({"action": action, "meta": meta}))
569
+ return 0
570
+
571
+ if argv and argv[0] == "--check":
572
+ ok, reason, action, meta = check_command(argv[1:])
573
+ print(json.dumps({"ok": ok, "reason": reason, "action": action, "meta": meta}))
574
+ return 0 if ok else 2
575
+
576
+ # Default: act as gh shim. Expect `--` then gh args, or raw gh args.
577
+ if argv and argv[0] == "--":
578
+ gh_args = argv[1:]
579
+ else:
580
+ gh_args = argv
581
+
582
+ cfg = gate_config_from_env()
583
+ ok, reason, action, meta = check_command(gh_args, cfg)
584
+ if not ok:
585
+ write_denial(
586
+ cfg.get("run_dir"),
587
+ {
588
+ "kind": "denied",
589
+ "action": action,
590
+ "reason": reason,
591
+ "argv": gh_args,
592
+ "meta": meta,
593
+ "tier": cfg.get("tier"),
594
+ "allowlist": cfg.get("allowlist"),
595
+ "deny": cfg.get("deny"),
596
+ },
597
+ )
598
+ print(f"[loop-gh-gate] DENIED {action or 'unknown'}: {reason}", file=sys.stderr)
599
+ return 78 # EX_CONFIG — distinctive for gate denial
600
+
601
+ real = cfg.get("real_gh") or shutil_which_gh()
602
+ if not real:
603
+ print("[loop-gh-gate] real gh not found (LOOP_GATE_REAL_GH unset)", file=sys.stderr)
604
+ return 127
605
+
606
+ if action:
607
+ # Audit allowed mutations.
608
+ run_dir = cfg.get("run_dir")
609
+ if run_dir:
610
+ audit = Path(run_dir) / "gate-allow.jsonl"
611
+ with audit.open("a", encoding="utf-8") as fh:
612
+ fh.write(json.dumps({
613
+ "ts": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
614
+ "kind": "allowed",
615
+ "action": action,
616
+ "reason": reason,
617
+ "argv": redact_argv(gh_args),
618
+ "meta": {k: v for k, v in meta.items() if k != "raw"},
619
+ }) + "\n")
620
+
621
+ result = subprocess.run([real, *gh_args])
622
+ return int(result.returncode)
623
+
624
+
625
+ if __name__ == "__main__":
626
+ sys.exit(main())