Skip to content

Commit 42c99fc

Browse files
authored
fix(registry): restore Skill pages broken by behavior rules (#436)
Nitro rewrites the text `import.meta.env` inside skilld-protocol's bundled rules to `globalThis._importMeta_.env`. The rules then fail their own lowercase check, detectBehaviors throws, and every Skill page answers 503. Patch the literal so the bundler cannot reach it, and make a rules failure return no behaviors instead of a 503.
1 parent 98d68e6 commit 42c99fc

5 files changed

Lines changed: 45 additions & 4 deletions

File tree

‎layers/registry/server/utils/skill-behaviors.ts‎

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,16 @@ export type SkillPageBehavior = Omit<Behavior, 'locations'> & {
1212
* The page holds SKILL.md and the file names the sync stored, never supporting
1313
* file content, so only those inputs reach the shared rules. `skilld run`
1414
* applies the same rules to every file.
15+
*
16+
* The panel is optional, so a rules failure returns no behaviors and reports
17+
* itself. On 2026-10-05 the bundled rules failed their own parse, and the
18+
* throw took every Skill page down with a 503.
1519
*/
1620
export function skillPageBehaviors(input: {
1721
raw: string | null
1822
assetPaths: readonly string[]
1923
source: { owner: string, repo: string, branch: string | null, skillPath: string | null }
20-
}): SkillPageBehavior[] {
24+
}, detect: typeof detectBehaviors = detectBehaviors): SkillPageBehavior[] {
2125
const files = [
2226
...(input.raw === null ? [] : [{ path: 'SKILL.md', text: input.raw }]),
2327
...input.assetPaths.map(path => ({ path })),
@@ -34,7 +38,19 @@ export function skillPageBehaviors(input: {
3438
})
3539
return file && location.line !== null ? `${file}#L${location.line}` : file
3640
}
37-
return detectBehaviors(files).map(behavior => ({
41+
let detected: Behavior[]
42+
try {
43+
detected = detect(files)
44+
}
45+
catch (error) {
46+
emitOperationalEvent(createWideEvent({
47+
operation: 'skill-behaviors',
48+
outcome: 'failed',
49+
reason: error instanceof Error ? error.message : String(error),
50+
}))
51+
return []
52+
}
53+
return detected.map(behavior => ({
3854
...behavior,
3955
locations: behavior.locations.map(location => ({ ...location, url: url(location) })),
4056
}))
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
diff --git a/dist/behaviors.mjs b/dist/behaviors.mjs
2+
index 901192e4a9fc582bfeb23b17aae8beb79861ef57..f5cabec0a991721d7ca8af58bfa83ec352dec05f 100644
3+
--- a/dist/behaviors.mjs
4+
+++ b/dist/behaviors.mjs
5+
@@ -418,7 +418,8 @@ var skill_behaviors_default = {
6+
"commands": [["printenv"]],
7+
"substrings": [
8+
"process.env",
9+
- "import.meta.env",
10+
+ // Split so a bundler that rewrites `import.meta` cannot reach the pattern.
11+
+ "import." + "meta.env",
12+
"deno.env",
13+
"bun.env",
14+
"os.environ",

‎pnpm-lock.yaml‎

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎pnpm-workspace.yaml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ pipelines:
178178
patchedDependencies:
179179
hookable@5.5.3: patches/hookable@5.5.3.patch
180180
hookable@6.1.1: patches/hookable@6.1.1.patch
181+
skilld-protocol@2.5.0: patches/skilld-protocol@2.5.0.patch
181182
catalog:
182183
'@antfu/eslint-config': ^9.3.0
183184
'@cloudflare/sandbox': 1.0.0

‎test/unit/skill-page-behaviors.test.ts‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,13 @@ describe('skillPageBehaviors', () => {
3434

3535
expect(scripts?.locations[0]?.url).toBeNull()
3636
})
37+
38+
// 2026-10-05: the bundled rules failed their own parse, and every Skill page answered 503.
39+
it('returns no behaviors, and keeps the page up, when the rules fail', () => {
40+
const failing = () => {
41+
throw new Error('patterns are lowercase')
42+
}
43+
44+
expect(skillPageBehaviors({ raw: '---\nname: setup\n---\n', assetPaths: ['run.py'], source }, failing)).toEqual([])
45+
})
3746
})

0 commit comments

Comments
 (0)