-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathaction.yml
More file actions
202 lines (173 loc) · 6.2 KB
/
action.yml
File metadata and controls
202 lines (173 loc) · 6.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
name: 'Context Lint'
description: 'Lint a URL for LLM readiness and token efficiency'
author: 'Hansel Wahjono'
branding:
icon: 'search'
color: 'blue'
inputs:
url:
description: 'URL to lint'
required: true
fail-under:
description: 'Fail if score is below this threshold (0-100)'
required: false
fail-on-blocked-bots:
description: 'Fail (exit 2) if any AI bot is blocked'
required: false
default: 'false'
single-page:
description: 'Lint only the given URL (skip multi-page discovery)'
required: false
default: 'false'
max-pages:
description: 'Maximum pages to lint in multi-page mode'
required: false
default: '10'
baseline-file:
description: 'Path to baseline JSON file to compare against (regression detection)'
required: false
save-baseline:
description: 'Path to save current scores as a baseline JSON file'
required: false
regression-threshold:
description: 'Minimum score drop to flag as regression (default: 5 points)'
required: false
default: '5'
robots-min:
description: 'Minimum robots.txt pillar score (0-25)'
required: false
schema-min:
description: 'Minimum Schema.org pillar score (0-25)'
required: false
content-min:
description: 'Minimum content density pillar score (0-40)'
required: false
llms-min:
description: 'Minimum llms.txt pillar score (0-10)'
required: false
overall-min:
description: 'Minimum overall score (0-100, alternative to fail-under)'
required: false
webhook-url:
description: 'Webhook URL to POST lint results to (Slack, Discord, etc.)'
required: false
max-context-waste:
description: 'Maximum acceptable context waste percentage (0-100). Fail if exceeded.'
required: false
default: ''
require-llms-txt:
description: 'Fail if llms.txt is not present on the site'
required: false
default: 'false'
require-bot-access:
description: 'Fail if any AI bots are blocked by robots.txt'
required: false
default: 'false'
python-version:
description: 'Python version to use'
required: false
default: '3.12'
outputs:
score:
description: 'Overall LLM readiness score (0-100)'
value: ${{ steps.lint.outputs.score }}
report-json:
description: 'Full lint report as JSON'
value: ${{ steps.lint.outputs.report_json }}
token-waste:
description: 'Context waste percentage from Token Waste analysis'
value: ${{ steps.lint.outputs.token_waste }}
runs:
using: 'composite'
steps:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python-version }}
cache: 'pip'
- name: Install context-cli
shell: bash
run: pip install context-linter
- name: Install crawl4ai browser
shell: bash
run: |
crawl4ai-setup || echo "::warning::crawl4ai browser setup failed, content analysis may be limited"
- name: Run Context Lint
id: lint
shell: bash
run: |
# Build command
CMD="context-cli lint '${{ inputs.url }}'"
if [ "${{ inputs.single-page }}" = "true" ]; then
CMD="$CMD --single"
else
CMD="$CMD --max-pages ${{ inputs.max-pages }}"
fi
CMD="$CMD --json"
# Run lint and capture JSON output
REPORT=$(eval $CMD 2>/dev/null || true)
# Extract score from JSON
SCORE=$(echo "$REPORT" | python3 -c "import sys, json; print(json.load(sys.stdin)['overall_score'])" 2>/dev/null || echo "0")
# Extract token waste from JSON
TOKEN_WASTE=$(echo "$REPORT" | python3 -c "
import sys, json
data = json.load(sys.stdin)
lr = data.get('lint_result')
if lr:
print(lr.get('context_waste_pct', 'N/A'))
else:
print('N/A')
" 2>/dev/null || echo "N/A")
echo "score=$SCORE" >> $GITHUB_OUTPUT
echo "token_waste=$TOKEN_WASTE" >> $GITHUB_OUTPUT
echo "report_json<<REPORT_EOF" >> $GITHUB_OUTPUT
echo "$REPORT" >> $GITHUB_OUTPUT
echo "REPORT_EOF" >> $GITHUB_OUTPUT
# Now run with formatting for the step summary
SUMMARY_CMD="context-cli lint '${{ inputs.url }}'"
if [ "${{ inputs.single-page }}" = "true" ]; then
SUMMARY_CMD="$SUMMARY_CMD --single"
else
SUMMARY_CMD="$SUMMARY_CMD --max-pages ${{ inputs.max-pages }}"
fi
if [ -n "${{ inputs.fail-under }}" ]; then
SUMMARY_CMD="$SUMMARY_CMD --fail-under ${{ inputs.fail-under }}"
fi
if [ "${{ inputs.fail-on-blocked-bots }}" = "true" ]; then
SUMMARY_CMD="$SUMMARY_CMD --fail-on-blocked-bots"
fi
if [ -n "${{ inputs.baseline-file }}" ]; then
SUMMARY_CMD="$SUMMARY_CMD --baseline '${{ inputs.baseline-file }}'"
SUMMARY_CMD="$SUMMARY_CMD --regression-threshold ${{ inputs.regression-threshold }}"
fi
if [ -n "${{ inputs.save-baseline }}" ]; then
SUMMARY_CMD="$SUMMARY_CMD --save-baseline '${{ inputs.save-baseline }}'"
fi
if [ -n "${{ inputs.robots-min }}" ]; then
SUMMARY_CMD="$SUMMARY_CMD --robots-min ${{ inputs.robots-min }}"
fi
if [ -n "${{ inputs.schema-min }}" ]; then
SUMMARY_CMD="$SUMMARY_CMD --schema-min ${{ inputs.schema-min }}"
fi
if [ -n "${{ inputs.content-min }}" ]; then
SUMMARY_CMD="$SUMMARY_CMD --content-min ${{ inputs.content-min }}"
fi
if [ -n "${{ inputs.llms-min }}" ]; then
SUMMARY_CMD="$SUMMARY_CMD --llms-min ${{ inputs.llms-min }}"
fi
if [ -n "${{ inputs.overall-min }}" ]; then
SUMMARY_CMD="$SUMMARY_CMD --overall-min ${{ inputs.overall-min }}"
fi
if [ -n "${{ inputs.webhook-url }}" ]; then
SUMMARY_CMD="$SUMMARY_CMD --webhook '${{ inputs.webhook-url }}'"
fi
if [ -n "${{ inputs.max-context-waste }}" ]; then
SUMMARY_CMD="$SUMMARY_CMD --max-context-waste ${{ inputs.max-context-waste }}"
fi
if [ "${{ inputs.require-llms-txt }}" = "true" ]; then
SUMMARY_CMD="$SUMMARY_CMD --require-llms-txt"
fi
if [ "${{ inputs.require-bot-access }}" = "true" ]; then
SUMMARY_CMD="$SUMMARY_CMD --require-bot-access"
fi
eval $SUMMARY_CMD