@arii/boomtick-mcp 0.3.3
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.
- package/.env.example +6 -0
- package/.mcp/schemas/agent.search_ddgs.json +1 -0
- package/.mcp/schemas/boomtick.health.json +1 -0
- package/.mcp/schemas/github.checkout_branch.json +1 -0
- package/.mcp/schemas/github.comment_triage_summary.json +1 -0
- package/.mcp/schemas/github.create_issue.json +1 -0
- package/.mcp/schemas/github.create_pull_request.json +1 -0
- package/.mcp/schemas/github.get_merge_conflict_files.json +1 -0
- package/.mcp/schemas/github.get_pr.json +1 -0
- package/.mcp/schemas/github.get_pr_diff.json +1 -0
- package/.mcp/schemas/github.issue_comment.json +1 -0
- package/.mcp/schemas/github.issue_update.json +1 -0
- package/.mcp/schemas/github.issue_view.json +1 -0
- package/.mcp/schemas/github.open_replacement_pr.json +1 -0
- package/.mcp/schemas/github.search_open_prs.json +1 -0
- package/.mcp/schemas/jules.cancel_session.json +1 -0
- package/.mcp/schemas/jules.create_session.json +1 -0
- package/.mcp/schemas/jules.get_messages.json +1 -0
- package/.mcp/schemas/jules.get_pr.json +1 -0
- package/.mcp/schemas/jules.get_session.json +1 -0
- package/.mcp/schemas/jules.list_sessions.json +1 -0
- package/.mcp/schemas/jules.send_message.json +1 -0
- package/.mcp/schemas/jules.trigger_feedback.json +1 -0
- package/.mcp/schemas/repo.commit_patch.json +1 -0
- package/.mcp/schemas/repo.create_branch.json +1 -0
- package/.mcp/schemas/repo.create_repair_branch.json +1 -0
- package/.mcp/schemas/repo.get_changed_files.json +1 -0
- package/.mcp/schemas/repo.get_command_schema.json +1 -0
- package/.mcp/schemas/repo.get_package_scripts.json +1 -0
- package/.mcp/schemas/repo.get_route_map.json +1 -0
- package/.mcp/schemas/repo.logs.json +1 -0
- package/.mcp/schemas/repo.read_agent_context.json +1 -0
- package/.mcp/schemas/repo.read_ci_logs.json +1 -0
- package/.mcp/schemas/repo.run_lighthouse.json +1 -0
- package/.mcp/schemas/repo.run_playwright.json +1 -0
- package/.mcp/schemas/repo.run_tests.json +1 -0
- package/CHANGELOG.md +50 -0
- package/README.md +108 -0
- package/actions/ai-review/action.yml +15 -0
- package/actions/audit/action.yml +37 -0
- package/actions/ci-validate/action.yml +9 -0
- package/actions/impact-analysis/action.yml +385 -0
- package/actions/lint-typecheck/action.yml +19 -0
- package/actions/run-project-gate/action.yml +163 -0
- package/actions/setup/action.yml +15 -0
- package/actions/setup-workspace/action.yml +179 -0
- package/actions/test-build/action.yml +71 -0
- package/actions/update-pr-comment/action.yml +101 -0
- package/dist/config.js +110 -0
- package/dist/evals/run-evals.js +38 -0
- package/dist/index.js +10 -0
- package/dist/lib/error_utils.js +8 -0
- package/dist/lib/git.js +33 -0
- package/dist/lib/result.js +21 -0
- package/dist/lib/shell.js +91 -0
- package/dist/lib/shell.test.js +10 -0
- package/dist/lib/td-cli.js +27 -0
- package/dist/lib/test-utils.js +20 -0
- package/dist/mcp/definitions.js +242 -0
- package/dist/mcp/server.js +317 -0
- package/dist/mcp/tools.js +18 -0
- package/dist/tools/contract.js +2069 -0
- package/dist/tools/ddgs.search.js +50 -0
- package/dist/tools/ddgs.search.test.js +67 -0
- package/dist/tools/ddgs_search.py +23 -0
- package/dist/tools/github.checkout_branch.js +20 -0
- package/dist/tools/github.comment_triage_summary.js +25 -0
- package/dist/tools/github.create_issue.js +28 -0
- package/dist/tools/github.create_issue.test.js +54 -0
- package/dist/tools/github.create_pull_request.js +44 -0
- package/dist/tools/github.get_merge_conflict_files.js +26 -0
- package/dist/tools/github.get_pr.js +18 -0
- package/dist/tools/github.get_pr_diff.js +24 -0
- package/dist/tools/github.issue_comment.js +24 -0
- package/dist/tools/github.issue_update.js +29 -0
- package/dist/tools/github.issue_view.js +28 -0
- package/dist/tools/github.open_replacement_pr.js +41 -0
- package/dist/tools/github.search_open_prs.js +31 -0
- package/dist/tools/github.search_open_prs.test.js +51 -0
- package/dist/tools/jules/cancel-session.js +20 -0
- package/dist/tools/jules/create-session.js +20 -0
- package/dist/tools/jules/create-session.test.js +99 -0
- package/dist/tools/jules/get-messages.js +19 -0
- package/dist/tools/jules/get-messages.test.js +45 -0
- package/dist/tools/jules/get-pr.js +14 -0
- package/dist/tools/jules/get-pr.test.js +37 -0
- package/dist/tools/jules/get-session.js +10 -0
- package/dist/tools/jules/list-sessions.js +43 -0
- package/dist/tools/jules/send-message.js +22 -0
- package/dist/tools/jules/send-message.test.js +56 -0
- package/dist/tools/jules/shared.js +26 -0
- package/dist/tools/jules/trigger-feedback.js +16 -0
- package/dist/tools/jules/trigger-feedback.test.js +42 -0
- package/dist/tools/repo.commit_patch.js +33 -0
- package/dist/tools/repo.create_branch.js +21 -0
- package/dist/tools/repo.create_branch.test.js +42 -0
- package/dist/tools/repo.create_repair_branch.js +38 -0
- package/dist/tools/repo.get_changed_files.js +21 -0
- package/dist/tools/repo.get_command_schema.js +27 -0
- package/dist/tools/repo.get_package_scripts.js +35 -0
- package/dist/tools/repo.get_package_scripts.test.js +39 -0
- package/dist/tools/repo.get_route_map.js +37 -0
- package/dist/tools/repo.logs.js +16 -0
- package/dist/tools/repo.read_agent_context.js +20 -0
- package/dist/tools/repo.read_ci_logs.js +18 -0
- package/dist/tools/repo.run_lighthouse.js +37 -0
- package/dist/tools/repo.run_playwright.js +29 -0
- package/dist/tools/repo.run_tests.js +43 -0
- package/dist/tools/types.js +1 -0
- package/docs/testing.md +73 -0
- package/package.json +45 -0
- package/scripts/create_instructions.sh +42 -0
- package/scripts/export-mcp-schema.ts +7 -0
- package/scripts/sync-contracts.ts +74 -0
- package/scripts/sync-mcp-schemas.ts +97 -0
- package/src/agents/conflict-scout.prompt.md +20 -0
- package/src/agents/pr-consolidation.prompt.md +32 -0
- package/src/agents/pr-writer.prompt.md +13 -0
- package/src/agents/repair-agent.prompt.md +18 -0
- package/src/agents/repo-context.prompt.md +20 -0
- package/src/agents/verifier-agent.prompt.md +22 -0
- package/src/config.ts +113 -0
- package/src/evals/fixtures/merge-conflict-simple/README.md +0 -0
- package/src/evals/run-evals.ts +40 -0
- package/src/index.ts +12 -0
- package/src/lib/error_utils.ts +8 -0
- package/src/lib/git.ts +41 -0
- package/src/lib/result.ts +28 -0
- package/src/lib/shell.test.ts +11 -0
- package/src/lib/shell.ts +118 -0
- package/src/lib/td-cli.ts +38 -0
- package/src/lib/test-utils.ts +23 -0
- package/src/mcp/definitions.ts +278 -0
- package/src/mcp/server.ts +359 -0
- package/src/mcp/tools.ts +20 -0
- package/src/tools/contract.ts +2245 -0
- package/src/tools/ddgs.search.test.ts +92 -0
- package/src/tools/ddgs.search.ts +58 -0
- package/src/tools/ddgs_search.py +23 -0
- package/src/tools/github.checkout_branch.ts +25 -0
- package/src/tools/github.comment_triage_summary.ts +30 -0
- package/src/tools/github.create_issue.test.ts +63 -0
- package/src/tools/github.create_issue.ts +34 -0
- package/src/tools/github.create_pull_request.ts +50 -0
- package/src/tools/github.get_merge_conflict_files.ts +31 -0
- package/src/tools/github.get_pr.ts +24 -0
- package/src/tools/github.get_pr_diff.ts +29 -0
- package/src/tools/github.issue_comment.ts +31 -0
- package/src/tools/github.issue_update.ts +31 -0
- package/src/tools/github.issue_view.ts +35 -0
- package/src/tools/github.open_replacement_pr.ts +48 -0
- package/src/tools/github.search_open_prs.test.ts +60 -0
- package/src/tools/github.search_open_prs.ts +40 -0
- package/src/tools/jules/cancel-session.ts +26 -0
- package/src/tools/jules/create-session.test.ts +114 -0
- package/src/tools/jules/create-session.ts +24 -0
- package/src/tools/jules/get-messages.test.ts +52 -0
- package/src/tools/jules/get-messages.ts +24 -0
- package/src/tools/jules/get-pr.test.ts +43 -0
- package/src/tools/jules/get-pr.ts +17 -0
- package/src/tools/jules/get-session.ts +12 -0
- package/src/tools/jules/list-sessions.ts +50 -0
- package/src/tools/jules/send-message.test.ts +66 -0
- package/src/tools/jules/send-message.ts +27 -0
- package/src/tools/jules/shared.ts +28 -0
- package/src/tools/jules/trigger-feedback.test.ts +50 -0
- package/src/tools/jules/trigger-feedback.ts +21 -0
- package/src/tools/repo.commit_patch.ts +41 -0
- package/src/tools/repo.create_branch.test.ts +55 -0
- package/src/tools/repo.create_branch.ts +29 -0
- package/src/tools/repo.create_repair_branch.ts +47 -0
- package/src/tools/repo.get_changed_files.ts +26 -0
- package/src/tools/repo.get_command_schema.ts +30 -0
- package/src/tools/repo.get_package_scripts.test.ts +51 -0
- package/src/tools/repo.get_package_scripts.ts +36 -0
- package/src/tools/repo.get_route_map.ts +41 -0
- package/src/tools/repo.logs.ts +21 -0
- package/src/tools/repo.read_agent_context.ts +22 -0
- package/src/tools/repo.read_ci_logs.ts +21 -0
- package/src/tools/repo.run_lighthouse.ts +40 -0
- package/src/tools/repo.run_playwright.ts +35 -0
- package/src/tools/repo.run_tests.ts +47 -0
- package/src/tools/types.ts +8 -0
- package/start_browsermcp.sh +14 -0
- package/start_github_mcp.sh +6 -0
- package/tsconfig.json +15 -0
- package/vitest.config.ts +9 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
name: BoomTick Impact Analysis
|
|
2
|
+
description: Comprehensive deployment impact analysis, diffing, AI reviews, and reporting
|
|
3
|
+
inputs:
|
|
4
|
+
github_token:
|
|
5
|
+
description: 'GitHub token'
|
|
6
|
+
required: true
|
|
7
|
+
gemini_api_key:
|
|
8
|
+
description: 'Gemini API key'
|
|
9
|
+
required: true
|
|
10
|
+
pr_number:
|
|
11
|
+
description: 'PR number'
|
|
12
|
+
required: true
|
|
13
|
+
jules_api_key:
|
|
14
|
+
description: 'Jules API key required for authenticating with the Jules API to send impact analysis results. Ensure this key is stored securely and not exposed in logs.'
|
|
15
|
+
required: true
|
|
16
|
+
runs:
|
|
17
|
+
using: composite
|
|
18
|
+
steps:
|
|
19
|
+
- uses: ./mcp/actions/setup
|
|
20
|
+
|
|
21
|
+
- run: pnpm install --frozen-lockfile --prefer-offline
|
|
22
|
+
shell: bash
|
|
23
|
+
|
|
24
|
+
- name: Deployment Impact Analysis
|
|
25
|
+
id: impact_analysis
|
|
26
|
+
env:
|
|
27
|
+
GITHUB_TOKEN: ${{ inputs.github_token }}
|
|
28
|
+
PR_NUMBER: ${{ inputs.pr_number }}
|
|
29
|
+
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
30
|
+
JULES_API_KEY: ${{ inputs.jules_api_key }}
|
|
31
|
+
run: |
|
|
32
|
+
if ! node -e "const pkg = require('./package.json'); if (!pkg.scripts || !pkg.scripts['impact:analysis']) process.exit(1)" 2>/dev/null; then
|
|
33
|
+
echo "⚠️ Skipping: impact:analysis script not found in package.json"
|
|
34
|
+
echo "has_impact=false" >> "$GITHUB_OUTPUT"
|
|
35
|
+
exit 0
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
pnpm run impact:analysis
|
|
39
|
+
|
|
40
|
+
# Determine has_impact based on generated report
|
|
41
|
+
if [ -f artifacts/impact-analysis/impact.json ]; then
|
|
42
|
+
ROUTES_COUNT=$(jq '.routes | length' artifacts/impact-analysis/impact.json 2>/dev/null || echo "0")
|
|
43
|
+
FILES_COUNT=$(jq '.changedFiles | length' artifacts/impact-analysis/impact.json 2>/dev/null || echo "0")
|
|
44
|
+
if [ "$ROUTES_COUNT" -gt 0 ] || [ "$FILES_COUNT" -gt 0 ]; then
|
|
45
|
+
echo "has_impact=true" >> "$GITHUB_OUTPUT"
|
|
46
|
+
else
|
|
47
|
+
echo "has_impact=false" >> "$GITHUB_OUTPUT"
|
|
48
|
+
fi
|
|
49
|
+
else
|
|
50
|
+
echo "has_impact=true" >> "$GITHUB_OUTPUT"
|
|
51
|
+
fi
|
|
52
|
+
shell: bash
|
|
53
|
+
|
|
54
|
+
- name: Build Main
|
|
55
|
+
if: steps.impact_analysis.outputs.has_impact == 'true'
|
|
56
|
+
env:
|
|
57
|
+
DISABLE_MINIFY: true
|
|
58
|
+
GITHUB_TOKEN: ${{ inputs.github_token }}
|
|
59
|
+
PR_NUMBER: ${{ inputs.pr_number }}
|
|
60
|
+
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
61
|
+
JULES_API_KEY: ${{ inputs.jules_api_key }}
|
|
62
|
+
run: |
|
|
63
|
+
if node -e "const pkg = require('./package.json'); if (!pkg.scripts || !pkg.scripts['impact:build-main']) process.exit(1)" 2>/dev/null; then
|
|
64
|
+
pnpm run impact:build-main
|
|
65
|
+
else
|
|
66
|
+
echo "⚠️ Skipping: impact:build-main script not found"
|
|
67
|
+
fi
|
|
68
|
+
shell: bash
|
|
69
|
+
|
|
70
|
+
- name: Build PR
|
|
71
|
+
if: steps.impact_analysis.outputs.has_impact == 'true'
|
|
72
|
+
env:
|
|
73
|
+
VITE_BASE_PATH: /
|
|
74
|
+
DISABLE_MINIFY: true
|
|
75
|
+
GITHUB_TOKEN: ${{ inputs.github_token }}
|
|
76
|
+
PR_NUMBER: ${{ inputs.pr_number }}
|
|
77
|
+
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
78
|
+
JULES_API_KEY: ${{ inputs.jules_api_key }}
|
|
79
|
+
run: |
|
|
80
|
+
if node -e "const pkg = require('./package.json'); if (!pkg.scripts || !pkg.scripts['build:review']) process.exit(1)" 2>/dev/null; then
|
|
81
|
+
pnpm run build:review
|
|
82
|
+
else
|
|
83
|
+
echo "⚠️ Skipping: build:review script not found"
|
|
84
|
+
fi
|
|
85
|
+
shell: bash
|
|
86
|
+
|
|
87
|
+
- name: Code review agent
|
|
88
|
+
if: always() && github.event_name == 'pull_request' && steps.impact_analysis.outputs.has_impact == 'true'
|
|
89
|
+
continue-on-error: true
|
|
90
|
+
env:
|
|
91
|
+
GEMINI_API_KEY: ${{ inputs.gemini_api_key }}
|
|
92
|
+
GITHUB_TOKEN: ${{ inputs.github_token }}
|
|
93
|
+
PR_NUMBER: ${{ inputs.pr_number }}
|
|
94
|
+
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
95
|
+
JULES_API_KEY: ${{ inputs.jules_api_key }}
|
|
96
|
+
run: |
|
|
97
|
+
if node -e "const pkg = require('./package.json'); if (!pkg.scripts || !pkg.scripts['impact:gemini-code-review']) process.exit(1)" 2>/dev/null; then
|
|
98
|
+
pnpm run impact:gemini-code-review
|
|
99
|
+
else
|
|
100
|
+
echo "⚠️ Skipping: impact:gemini-code-review script not found"
|
|
101
|
+
fi
|
|
102
|
+
shell: bash
|
|
103
|
+
|
|
104
|
+
- name: Code review github models agent
|
|
105
|
+
if: always() && github.event_name == 'pull_request' && steps.impact_analysis.outputs.has_impact == 'true'
|
|
106
|
+
continue-on-error: true
|
|
107
|
+
env:
|
|
108
|
+
GITHUB_TOKEN: ${{ inputs.github_token }}
|
|
109
|
+
PR_NUMBER: ${{ inputs.pr_number }}
|
|
110
|
+
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
111
|
+
JULES_API_KEY: ${{ inputs.jules_api_key }}
|
|
112
|
+
run: |
|
|
113
|
+
if node -e "const pkg = require('./package.json'); if (!pkg.scripts || !pkg.scripts['impact:github-models-code-review']) process.exit(1)" 2>/dev/null; then
|
|
114
|
+
pnpm run impact:github-models-code-review
|
|
115
|
+
else
|
|
116
|
+
echo "⚠️ Skipping: impact:github-models-code-review script not found"
|
|
117
|
+
fi
|
|
118
|
+
shell: bash
|
|
119
|
+
|
|
120
|
+
- name: Visual Diff
|
|
121
|
+
if: steps.impact_analysis.outputs.has_impact == 'true'
|
|
122
|
+
env:
|
|
123
|
+
GITHUB_TOKEN: ${{ inputs.github_token }}
|
|
124
|
+
PR_NUMBER: ${{ inputs.pr_number }}
|
|
125
|
+
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
126
|
+
JULES_API_KEY: ${{ inputs.jules_api_key }}
|
|
127
|
+
run: |
|
|
128
|
+
if node -e "const pkg = require('./package.json'); if (!pkg.scripts || !pkg.scripts['impact:visual-diff']) process.exit(1)" 2>/dev/null; then
|
|
129
|
+
pnpm run impact:visual-diff
|
|
130
|
+
else
|
|
131
|
+
echo "⚠️ Skipping: impact:visual-diff script not found"
|
|
132
|
+
fi
|
|
133
|
+
shell: bash
|
|
134
|
+
|
|
135
|
+
- name: DOM Diff
|
|
136
|
+
if: steps.impact_analysis.outputs.has_impact == 'true'
|
|
137
|
+
env:
|
|
138
|
+
GITHUB_TOKEN: ${{ inputs.github_token }}
|
|
139
|
+
PR_NUMBER: ${{ inputs.pr_number }}
|
|
140
|
+
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
141
|
+
JULES_API_KEY: ${{ inputs.jules_api_key }}
|
|
142
|
+
run: |
|
|
143
|
+
if node -e "const pkg = require('./package.json'); if (!pkg.scripts || !pkg.scripts['impact:dom-diff']) process.exit(1)" 2>/dev/null; then
|
|
144
|
+
pnpm run impact:dom-diff
|
|
145
|
+
else
|
|
146
|
+
echo "⚠️ Skipping: impact:dom-diff script not found"
|
|
147
|
+
fi
|
|
148
|
+
shell: bash
|
|
149
|
+
|
|
150
|
+
- name: Check if visual changes exist
|
|
151
|
+
if: steps.impact_analysis.outputs.has_impact == 'true'
|
|
152
|
+
id: check_visuals
|
|
153
|
+
env:
|
|
154
|
+
VISUAL_DIFF_THRESHOLD: 1.5
|
|
155
|
+
run: |
|
|
156
|
+
SCRIPT_PATH=""
|
|
157
|
+
if [ -f "scripts/check-visual-changes.ts" ]; then
|
|
158
|
+
SCRIPT_PATH="scripts/check-visual-changes.ts"
|
|
159
|
+
elif [ -f "${{ github.action_path }}/../../../scripts/check-visual-changes.ts" ]; then
|
|
160
|
+
SCRIPT_PATH="${{ github.action_path }}/../../../scripts/check-visual-changes.ts"
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
if [[ -n "$SCRIPT_PATH" && ( "$SCRIPT_PATH" == *"/scripts/check-visual-changes.ts" || "$SCRIPT_PATH" == "scripts/check-visual-changes.ts" ) ]]; then
|
|
164
|
+
RESOLVED_PATH=$(realpath "$SCRIPT_PATH")
|
|
165
|
+
if [[ -f "$RESOLVED_PATH" && "$RESOLVED_PATH" == *"/scripts/check-visual-changes.ts" ]]; then
|
|
166
|
+
echo "Executing check-visual-changes.ts at: $RESOLVED_PATH"
|
|
167
|
+
pnpm exec tsx "$RESOLVED_PATH" >> "$GITHUB_OUTPUT"
|
|
168
|
+
else
|
|
169
|
+
echo "❌ Error: Resolved path validation failed for $RESOLVED_PATH. Defaulting changed_routes=0"
|
|
170
|
+
echo "changed_routes=0" >> "$GITHUB_OUTPUT"
|
|
171
|
+
fi
|
|
172
|
+
else
|
|
173
|
+
echo "⚠️ Skipping: check-visual-changes.ts script not found or validation failed. Defaulting changed_routes=0"
|
|
174
|
+
echo "changed_routes=0" >> "$GITHUB_OUTPUT"
|
|
175
|
+
fi
|
|
176
|
+
shell: bash
|
|
177
|
+
|
|
178
|
+
- name: Visual review agent
|
|
179
|
+
if: always() && steps.check_visuals.outputs.changed_routes != '0' && steps.check_visuals.outputs.changed_routes != ''
|
|
180
|
+
env:
|
|
181
|
+
GEMINI_API_KEY: ${{ inputs.gemini_api_key }}
|
|
182
|
+
GITHUB_TOKEN: ${{ inputs.github_token }}
|
|
183
|
+
PR_NUMBER: ${{ inputs.pr_number }}
|
|
184
|
+
JULES_API_KEY: ${{ inputs.jules_api_key }}
|
|
185
|
+
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
186
|
+
run: |
|
|
187
|
+
if node -e "const pkg = require('./package.json'); if (!pkg.scripts || !pkg.scripts['impact:gemini-review']) process.exit(1)" 2>/dev/null; then
|
|
188
|
+
pnpm run impact:gemini-review
|
|
189
|
+
else
|
|
190
|
+
echo "⚠️ Skipping: impact:gemini-review script not found"
|
|
191
|
+
fi
|
|
192
|
+
shell: bash
|
|
193
|
+
|
|
194
|
+
- name: Visual review github models agent
|
|
195
|
+
if: always() && steps.check_visuals.outputs.changed_routes != '0' && steps.check_visuals.outputs.changed_routes != ''
|
|
196
|
+
env:
|
|
197
|
+
GITHUB_TOKEN: ${{ inputs.github_token }}
|
|
198
|
+
PR_NUMBER: ${{ inputs.pr_number }}
|
|
199
|
+
JULES_API_KEY: ${{ inputs.jules_api_key }}
|
|
200
|
+
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
201
|
+
run: |
|
|
202
|
+
if node -e "const pkg = require('./package.json'); if (!pkg.scripts || !pkg.scripts['impact:github-models-review']) process.exit(1)" 2>/dev/null; then
|
|
203
|
+
pnpm run impact:github-models-review
|
|
204
|
+
else
|
|
205
|
+
echo "⚠️ Skipping: impact:github-models-review script not found"
|
|
206
|
+
fi
|
|
207
|
+
shell: bash
|
|
208
|
+
|
|
209
|
+
- name: Report Summary
|
|
210
|
+
if: always()
|
|
211
|
+
run: |
|
|
212
|
+
if [ -f artifacts/deployment-review.md ]; then
|
|
213
|
+
cat artifacts/deployment-review.md >> "$GITHUB_STEP_SUMMARY"
|
|
214
|
+
{
|
|
215
|
+
echo "IMPACT_BODY<<EOF"
|
|
216
|
+
cat artifacts/deployment-review.md
|
|
217
|
+
echo "EOF"
|
|
218
|
+
} >> "$GITHUB_ENV"
|
|
219
|
+
elif [ -f artifacts/impact-analysis/impact.md ]; then
|
|
220
|
+
cat artifacts/impact-analysis/impact.md >> "$GITHUB_STEP_SUMMARY"
|
|
221
|
+
{
|
|
222
|
+
echo "IMPACT_BODY<<EOF"
|
|
223
|
+
cat artifacts/impact-analysis/impact.md
|
|
224
|
+
echo "EOF"
|
|
225
|
+
} >> "$GITHUB_ENV"
|
|
226
|
+
else
|
|
227
|
+
{
|
|
228
|
+
echo "## Deployment Impact Analysis"
|
|
229
|
+
echo "No impact report found."
|
|
230
|
+
} >> "$GITHUB_STEP_SUMMARY"
|
|
231
|
+
{
|
|
232
|
+
echo "IMPACT_BODY<<EOF"
|
|
233
|
+
echo "No impact report found."
|
|
234
|
+
echo "EOF"
|
|
235
|
+
} >> "$GITHUB_ENV"
|
|
236
|
+
fi
|
|
237
|
+
|
|
238
|
+
if [ -f artifacts/gemini-review.md ]; then
|
|
239
|
+
{ echo ""; cat artifacts/gemini-review.md; } >> "$GITHUB_STEP_SUMMARY"
|
|
240
|
+
fi
|
|
241
|
+
if [ -f artifacts/github-models-review.md ]; then
|
|
242
|
+
{ echo ""; cat artifacts/github-models-review.md; } >> "$GITHUB_STEP_SUMMARY"
|
|
243
|
+
fi
|
|
244
|
+
if [ -f artifacts/gemini-code-review.md ]; then
|
|
245
|
+
{ echo ""; cat artifacts/gemini-code-review.md; } >> "$GITHUB_STEP_SUMMARY"
|
|
246
|
+
fi
|
|
247
|
+
if [ -f artifacts/github-models-code-review.md ]; then
|
|
248
|
+
{ echo ""; cat artifacts/github-models-code-review.md; } >> "$GITHUB_STEP_SUMMARY"
|
|
249
|
+
fi
|
|
250
|
+
|
|
251
|
+
FAILED=0
|
|
252
|
+
# Expected verdicts: gemini-code-review, github-models-code-review
|
|
253
|
+
# Visual reviews are expected only if visual changes exist
|
|
254
|
+
EXPECTED_REVIEWS=""
|
|
255
|
+
if [ "${{ steps.impact_analysis.outputs.has_impact }}" == "true" ]; then
|
|
256
|
+
if [ "${{ github.event_name }}" == "pull_request" ]; then
|
|
257
|
+
EXPECTED_REVIEWS="gemini-code-review github-models-code-review"
|
|
258
|
+
fi
|
|
259
|
+
if [ "${{ steps.check_visuals.outputs.changed_routes }}" != "0" ] && [ "${{ steps.check_visuals.outputs.changed_routes }}" != "" ]; then
|
|
260
|
+
EXPECTED_REVIEWS="$EXPECTED_REVIEWS gemini-review github-models-review"
|
|
261
|
+
fi
|
|
262
|
+
fi
|
|
263
|
+
|
|
264
|
+
for r in $EXPECTED_REVIEWS; do
|
|
265
|
+
f="artifacts/$r-verdict.json"
|
|
266
|
+
if [ ! -f "$f" ]; then
|
|
267
|
+
echo "❌ Expected review verdict file missing: $f. The review script may have crashed." >&2
|
|
268
|
+
FAILED=1
|
|
269
|
+
continue
|
|
270
|
+
fi
|
|
271
|
+
|
|
272
|
+
PASSED=$(jq -r '.passed | if type == "null" or type == "nan" then "error" else . end' "$f" 2>/dev/null || echo "error")
|
|
273
|
+
VERDICT=$(jq -r '.llmVerdict | if type == "null" or type == "nan" then "unknown" else . end' "$f" 2>/dev/null || echo "unknown")
|
|
274
|
+
HIGH=$(jq -r '.highCount | if type == "null" or type == "nan" then "0" else . end' "$f" 2>/dev/null || echo "0")
|
|
275
|
+
|
|
276
|
+
if [[ "$VERDICT" == "warn" ]]; then
|
|
277
|
+
# Only allow specific safe-skip reasons for warnings to pass CI
|
|
278
|
+
IS_TRUNCATED=$(jq -r '.isTruncated // .truncated // "false"' "$f" 2>/dev/null)
|
|
279
|
+
SKIP_REASON=$(jq -r '.skipReason // "NONE"' "$f" 2>/dev/null)
|
|
280
|
+
|
|
281
|
+
if [[ "$IS_TRUNCATED" == "true" || "$SKIP_REASON" == *"MISSING_API_KEY"* || "$SKIP_REASON" == *"RATE_LIMIT"* || "$SKIP_REASON" == *"UNHANDLED_ERROR"* || "$SKIP_REASON" == *"TRUNCATED"* || "$SKIP_REASON" == *"PARSE_ERROR"* || "$SKIP_REASON" == "NONE" ]]; then
|
|
282
|
+
echo "⚠️ Review Warning: Legitimate skip/truncation ($f, reason: $SKIP_REASON, truncated: $IS_TRUNCATED). Manual review recommended."
|
|
283
|
+
else
|
|
284
|
+
echo "❌ Review failed: Unexpected warning state ($f, reason: $SKIP_REASON)" >&2
|
|
285
|
+
FAILED=1
|
|
286
|
+
fi
|
|
287
|
+
fi
|
|
288
|
+
|
|
289
|
+
if [[ "$PASSED" == "false" || "$VERDICT" == "fail" ]]; then
|
|
290
|
+
echo "❌ Review failed: $HIGH HIGH severity issues found ($f)" >&2
|
|
291
|
+
FAILED=1
|
|
292
|
+
elif [ "$PASSED" = "error" ]; then
|
|
293
|
+
echo "❌ Review failed: Could not parse verdict file ($f). Review may be malformed." >&2
|
|
294
|
+
FAILED=1
|
|
295
|
+
fi
|
|
296
|
+
done
|
|
297
|
+
exit $FAILED
|
|
298
|
+
shell: bash
|
|
299
|
+
|
|
300
|
+
- name: Parse Jules session ID from PR description
|
|
301
|
+
if: always()
|
|
302
|
+
id: parse_jules
|
|
303
|
+
env:
|
|
304
|
+
PR_BODY: ${{ github.event.pull_request.body }}
|
|
305
|
+
run: |
|
|
306
|
+
TASK_ID=$(echo "$PR_BODY" | grep -oP 'jules\.google\.com/task/\K[0-9]+' | head -1 || true)
|
|
307
|
+
if [ -z "$TASK_ID" ]; then
|
|
308
|
+
echo "No Jules task ID found in PR description. Skipping."
|
|
309
|
+
exit 0
|
|
310
|
+
fi
|
|
311
|
+
echo "Found Jules task ID: $TASK_ID"
|
|
312
|
+
echo "task_id=$TASK_ID" >> "$GITHUB_OUTPUT"
|
|
313
|
+
shell: bash
|
|
314
|
+
|
|
315
|
+
- name: Send impact analysis to Jules session
|
|
316
|
+
if: always() && steps.parse_jules.outputs.task_id != ''
|
|
317
|
+
env:
|
|
318
|
+
TASK_ID: ${{ steps.parse_jules.outputs.task_id }}
|
|
319
|
+
JULES_API_KEY: ${{ inputs.jules_api_key }}
|
|
320
|
+
GITHUB_TOKEN: ${{ inputs.github_token }}
|
|
321
|
+
PR_NUMBER: ${{ inputs.pr_number }}
|
|
322
|
+
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
323
|
+
run: |
|
|
324
|
+
if [ -f "scripts/send-jules-impact.py" ]; then
|
|
325
|
+
python3 scripts/send-jules-impact.py
|
|
326
|
+
elif [ -f "${{ github.action_path }}/../../../scripts/send-jules-impact.py" ]; then
|
|
327
|
+
python3 "${{ github.action_path }}/../../../scripts/send-jules-impact.py"
|
|
328
|
+
else
|
|
329
|
+
echo "⚠️ Skipping: send-jules-impact.py script not found"
|
|
330
|
+
fi
|
|
331
|
+
shell: bash
|
|
332
|
+
|
|
333
|
+
- name: Update Impact Analysis Feedback (Final Result)
|
|
334
|
+
if: always()
|
|
335
|
+
uses: ./mcp/actions/update-pr-comment
|
|
336
|
+
with:
|
|
337
|
+
github_token: ${{ inputs.github_token }}
|
|
338
|
+
status_line: '✅ **Impact Analysis Complete**'
|
|
339
|
+
impact_body: ${{ env.IMPACT_BODY }}
|
|
340
|
+
|
|
341
|
+
- name: Merge AI Logs into Artifacts
|
|
342
|
+
if: always()
|
|
343
|
+
run: |
|
|
344
|
+
# Ensure log directories exist
|
|
345
|
+
mkdir -p .boomtick/logs/ai
|
|
346
|
+
mkdir -p artifacts/logs/ai
|
|
347
|
+
|
|
348
|
+
# Sync from the TS logger location to the workspace log location expected by Python CLI
|
|
349
|
+
# Try both submodule and standalone paths
|
|
350
|
+
for log_dir in "cli/logs/ai"; do
|
|
351
|
+
if [ -d "$log_dir" ] && [ "$(ls -A "$log_dir" 2>/dev/null)" ]; then
|
|
352
|
+
cp -r "$log_dir"/* .boomtick/logs/ai/ 2>/dev/null || true
|
|
353
|
+
fi
|
|
354
|
+
done
|
|
355
|
+
|
|
356
|
+
# Sync to artifacts for upload
|
|
357
|
+
if [ -d .boomtick/logs/ai ] && [ "$(ls -A .boomtick/logs/ai 2>/dev/null)" ]; then
|
|
358
|
+
cp -r .boomtick/logs/ai/* artifacts/logs/ai/ 2>/dev/null || true
|
|
359
|
+
fi
|
|
360
|
+
shell: bash
|
|
361
|
+
|
|
362
|
+
- name: Upload Deployment Review Artifacts
|
|
363
|
+
if: always()
|
|
364
|
+
uses: actions/upload-artifact@v7 # nosemgrep: yaml.github-actions.security.github-actions-mutable-action-tag.github-actions-mutable-action-tag
|
|
365
|
+
with:
|
|
366
|
+
name: deployment-review
|
|
367
|
+
path: artifacts/
|
|
368
|
+
|
|
369
|
+
- name: Verify CI Metrics
|
|
370
|
+
if: always()
|
|
371
|
+
env:
|
|
372
|
+
GITHUB_TOKEN: ${{ inputs.github_token }}
|
|
373
|
+
run: |
|
|
374
|
+
# Resolve CLI dir for PYTHONPATH
|
|
375
|
+
if [ -d "cli" ]; then
|
|
376
|
+
export PYTHONPATH="cli:$PYTHONPATH"
|
|
377
|
+
fi
|
|
378
|
+
|
|
379
|
+
mkdir -p .boomtick/logs/ai
|
|
380
|
+
python3 -m dev_tools.cli gh summary-report >> "$GITHUB_STEP_SUMMARY"
|
|
381
|
+
if ! python3 -m dev_tools.cli gh verify-metrics; then
|
|
382
|
+
echo "CI Metrics verification failed."
|
|
383
|
+
exit 1
|
|
384
|
+
fi
|
|
385
|
+
shell: bash
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: BoomTick Lint & Typecheck
|
|
2
|
+
description: Runs linting and typechecking via project gate
|
|
3
|
+
inputs:
|
|
4
|
+
target:
|
|
5
|
+
description: 'Target to check (root or boomtick-mcp)'
|
|
6
|
+
required: true
|
|
7
|
+
github_token:
|
|
8
|
+
description: 'GitHub token'
|
|
9
|
+
required: true
|
|
10
|
+
runs:
|
|
11
|
+
using: composite
|
|
12
|
+
steps:
|
|
13
|
+
- uses: ./mcp/actions/setup
|
|
14
|
+
|
|
15
|
+
- name: Run Project Gate
|
|
16
|
+
uses: ./mcp/actions/run-project-gate
|
|
17
|
+
with:
|
|
18
|
+
target: ${{ inputs.target }}
|
|
19
|
+
github_token: ${{ inputs.github_token }}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
name: "Run Project Gate"
|
|
2
|
+
description: "Abstracted logic for building and testing monorepo sub-projects"
|
|
3
|
+
inputs:
|
|
4
|
+
target:
|
|
5
|
+
description: "Target project to validate (e.g., 'root', 'boomtick-mcp')"
|
|
6
|
+
required: true
|
|
7
|
+
github_token:
|
|
8
|
+
description: "GitHub token for API access (e.g., ratchet-any)"
|
|
9
|
+
required: false
|
|
10
|
+
|
|
11
|
+
runs:
|
|
12
|
+
using: "composite"
|
|
13
|
+
steps:
|
|
14
|
+
- name: Resolve Project Paths
|
|
15
|
+
id: resolve-paths
|
|
16
|
+
shell: bash
|
|
17
|
+
env:
|
|
18
|
+
TARGET: ${{ inputs.target }}
|
|
19
|
+
run: |
|
|
20
|
+
# Use centralized script for CLI path resolution
|
|
21
|
+
if [ -f "scripts/resolve-cli.sh" ]; then
|
|
22
|
+
CLI_PATH=$(bash scripts/resolve-cli.sh | sed "s|$(pwd)/||")
|
|
23
|
+
elif [ -f "boomtick-pkg/scripts/resolve-cli.sh" ]; then
|
|
24
|
+
CLI_PATH=$(bash boomtick-pkg/scripts/resolve-cli.sh | sed "s|$(pwd)/||")
|
|
25
|
+
elif [ -f "boomtick/scripts/resolve-cli.sh" ]; then
|
|
26
|
+
CLI_PATH=$(bash boomtick/scripts/resolve-cli.sh | sed "s|$(pwd)/||")
|
|
27
|
+
elif [ -d "boomtick-pkg/cli" ]; then
|
|
28
|
+
CLI_PATH="boomtick-pkg/cli"
|
|
29
|
+
elif [ -d "boomtick/cli" ]; then
|
|
30
|
+
CLI_PATH="boomtick/cli"
|
|
31
|
+
elif [ -d "cli" ]; then
|
|
32
|
+
CLI_PATH="cli"
|
|
33
|
+
else
|
|
34
|
+
CLI_PATH="cli"
|
|
35
|
+
fi
|
|
36
|
+
echo "CLI_PATH=$CLI_PATH" >> "$GITHUB_OUTPUT"
|
|
37
|
+
|
|
38
|
+
case "$TARGET" in
|
|
39
|
+
root)
|
|
40
|
+
echo "FILTER_PATH=." >> "$GITHUB_OUTPUT"
|
|
41
|
+
;;
|
|
42
|
+
boomtick-mcp)
|
|
43
|
+
if [ -d "mcp" ]; then
|
|
44
|
+
echo "FILTER_PATH=./mcp" >> "$GITHUB_OUTPUT"
|
|
45
|
+
else
|
|
46
|
+
echo "FILTER_PATH=./mcp" >> "$GITHUB_OUTPUT"
|
|
47
|
+
fi
|
|
48
|
+
;;
|
|
49
|
+
*)
|
|
50
|
+
echo "::error::Invalid target: $TARGET. Must be 'root' or 'boomtick-mcp'."
|
|
51
|
+
exit 1
|
|
52
|
+
;;
|
|
53
|
+
esac
|
|
54
|
+
|
|
55
|
+
- name: Validate Runtime
|
|
56
|
+
if: inputs.target == 'root'
|
|
57
|
+
run: |
|
|
58
|
+
echo "::group::Validate Runtime"
|
|
59
|
+
trap 'echo "::endgroup::"' EXIT
|
|
60
|
+
pnpm run check:runtime-files
|
|
61
|
+
pnpm run doctor
|
|
62
|
+
shell: bash
|
|
63
|
+
|
|
64
|
+
- name: pnpm install
|
|
65
|
+
env:
|
|
66
|
+
TARGET: ${{ inputs.target }}
|
|
67
|
+
FILTER_PATH: ${{ steps.resolve-paths.outputs.FILTER_PATH }}
|
|
68
|
+
run: |
|
|
69
|
+
echo "::group::pnpm install"
|
|
70
|
+
trap 'echo "::endgroup::"' EXIT
|
|
71
|
+
if [ "$TARGET" = "root" ]; then
|
|
72
|
+
pnpm install --frozen-lockfile --engine-strict=false
|
|
73
|
+
else
|
|
74
|
+
pnpm install --frozen-lockfile --filter "$FILTER_PATH" --engine-strict=false
|
|
75
|
+
fi
|
|
76
|
+
shell: bash
|
|
77
|
+
|
|
78
|
+
- name: Verify lockfile integrity (root only)
|
|
79
|
+
if: inputs.target == 'root'
|
|
80
|
+
run: |
|
|
81
|
+
if ! git diff --quiet pnpm-lock.yaml; then
|
|
82
|
+
echo "::error::pnpm-lock.yaml is out of date. Run pnpm install and commit."
|
|
83
|
+
exit 1
|
|
84
|
+
fi
|
|
85
|
+
shell: bash
|
|
86
|
+
|
|
87
|
+
- name: Lint
|
|
88
|
+
if: inputs.target == 'root'
|
|
89
|
+
run: |
|
|
90
|
+
pnpm run verify:schemas
|
|
91
|
+
pnpm run lint
|
|
92
|
+
shell: bash
|
|
93
|
+
|
|
94
|
+
- name: Type-check / Build
|
|
95
|
+
env:
|
|
96
|
+
TARGET: ${{ inputs.target }}
|
|
97
|
+
CLI_PATH: ${{ steps.resolve-paths.outputs.CLI_PATH }}
|
|
98
|
+
FILTER_PATH: ${{ steps.resolve-paths.outputs.FILTER_PATH }}
|
|
99
|
+
run: |
|
|
100
|
+
if [ "$TARGET" = "boomtick-mcp" ]; then
|
|
101
|
+
PYTHONPATH="$CLI_PATH" python3 "$CLI_PATH/dev_tools/schema_gen.py"
|
|
102
|
+
npx tsx "$FILTER_PATH/scripts/sync-contracts.ts"
|
|
103
|
+
pnpm --filter "$FILTER_PATH" run sync:mcp-schemas
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
if [ "$TARGET" = "root" ]; then
|
|
107
|
+
pnpm run type-check
|
|
108
|
+
else
|
|
109
|
+
pnpm --filter "$FILTER_PATH" run build
|
|
110
|
+
fi
|
|
111
|
+
shell: bash
|
|
112
|
+
|
|
113
|
+
- name: Python Linting
|
|
114
|
+
if: inputs.target == 'root'
|
|
115
|
+
continue-on-error: true
|
|
116
|
+
run: |
|
|
117
|
+
echo "::group::Python Linting"
|
|
118
|
+
trap 'echo "::endgroup::"' EXIT
|
|
119
|
+
if [ -f "requirements-dev.txt" ]; then
|
|
120
|
+
pip install -r requirements-dev.txt
|
|
121
|
+
fi
|
|
122
|
+
pnpm run lint:python
|
|
123
|
+
pnpm run type-check:python
|
|
124
|
+
shell: bash
|
|
125
|
+
|
|
126
|
+
- name: Run Unit Tests
|
|
127
|
+
env:
|
|
128
|
+
TARGET: ${{ inputs.target }}
|
|
129
|
+
FILTER_PATH: ${{ steps.resolve-paths.outputs.FILTER_PATH }}
|
|
130
|
+
run: |
|
|
131
|
+
if [ "$TARGET" = "root" ]; then
|
|
132
|
+
pnpm test
|
|
133
|
+
else
|
|
134
|
+
pnpm --filter "$FILTER_PATH" run test
|
|
135
|
+
fi
|
|
136
|
+
shell: bash
|
|
137
|
+
|
|
138
|
+
- name: Run CLI Unit Tests
|
|
139
|
+
if: inputs.target == 'root' || inputs.target == 'boomtick-mcp'
|
|
140
|
+
env:
|
|
141
|
+
CLI_PATH: ${{ steps.resolve-paths.outputs.CLI_PATH }}
|
|
142
|
+
run: |
|
|
143
|
+
echo "::group::Pytest"
|
|
144
|
+
trap 'echo "::endgroup::"' EXIT
|
|
145
|
+
PYTHONPATH="$CLI_PATH:$CLI_PATH/dev_tools" python3 -m pytest "$CLI_PATH/tests/"
|
|
146
|
+
shell: bash
|
|
147
|
+
|
|
148
|
+
- name: Check for dead code
|
|
149
|
+
if: inputs.target == 'root'
|
|
150
|
+
run: pnpm run knip
|
|
151
|
+
shell: bash
|
|
152
|
+
|
|
153
|
+
- name: TypeScript 'any' Ratchet
|
|
154
|
+
if: inputs.target == 'root'
|
|
155
|
+
run: |
|
|
156
|
+
echo "::group::Ratchet Any"
|
|
157
|
+
trap 'echo "::endgroup::"' EXIT
|
|
158
|
+
export PYTHONPATH="${{ steps.resolve-paths.outputs.CLI_PATH }}:${{ steps.resolve-paths.outputs.CLI_PATH }}/dev_tools"
|
|
159
|
+
export PATH="$HOME/.local/bin:/github/home/.local/bin:$PATH"
|
|
160
|
+
python3 -m dev_tools.cli gh ratchet-any
|
|
161
|
+
env:
|
|
162
|
+
GITHUB_TOKEN: ${{ inputs.github_token }}
|
|
163
|
+
shell: bash
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
name: BoomTick Setup
|
|
2
|
+
description: Comprehensive setup including checkout, node/pnpm, workspace, and MCP build
|
|
3
|
+
runs:
|
|
4
|
+
using: composite
|
|
5
|
+
steps:
|
|
6
|
+
- name: Configure Git Safe Directory
|
|
7
|
+
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
|
8
|
+
shell: bash
|
|
9
|
+
|
|
10
|
+
- name: Setup Workspace
|
|
11
|
+
uses: ./mcp/actions/setup-workspace
|
|
12
|
+
|
|
13
|
+
- name: Verify setup
|
|
14
|
+
run: python3 -m dev_tools.cli doctor
|
|
15
|
+
shell: bash
|