@sentry/junior 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/junior.mjs +11 -1
- package/dist/{bot-PFLNB5PC.js → bot-HXAROQ33.js} +5 -3
- package/dist/{chunk-BKYYVLVN.js → chunk-5UJSQX4R.js} +18 -482
- package/dist/{chunk-ECEC25CR.js → chunk-EZ6WIJL2.js} +1 -1
- package/dist/chunk-KT5HARSN.js +164 -0
- package/dist/{chunk-3ENACZ27.js → chunk-QNOV65P4.js} +321 -216
- package/dist/{chunk-WM5Z766B.js → chunk-VPCCZ3PK.js} +2 -2
- package/dist/chunk-VW26MOSO.js +522 -0
- package/dist/cli/check.d.ts +8 -0
- package/dist/cli/check.js +303 -0
- package/dist/cli/init.js +7 -0
- package/dist/cli/run.d.ts +2 -1
- package/dist/cli/run.js +9 -1
- package/dist/cli/snapshot-warmup.js +3 -2
- package/dist/handlers/queue-callback.js +6 -4
- package/dist/handlers/router.js +7 -5
- package/dist/handlers/webhooks.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// src/chat/skill-frontmatter.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { parse as parseYaml } from "yaml";
|
|
4
|
+
var FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
|
|
5
|
+
var SKILL_NAME_RE = /^[a-z0-9-]+$/;
|
|
6
|
+
var CAPABILITY_TOKEN_RE = /^[a-z0-9]+(?:\.[a-z0-9-]+)+$/;
|
|
7
|
+
var MAX_NAME_LENGTH = 64;
|
|
8
|
+
var MAX_DESCRIPTION_LENGTH = 1024;
|
|
9
|
+
var MAX_COMPATIBILITY_LENGTH = 500;
|
|
10
|
+
function hasAngleBrackets(value) {
|
|
11
|
+
return value.includes("<") || value.includes(">");
|
|
12
|
+
}
|
|
13
|
+
function validateSkillName(name) {
|
|
14
|
+
if (!name) return "name must not be empty";
|
|
15
|
+
if (name.length > MAX_NAME_LENGTH)
|
|
16
|
+
return `name must be <= ${MAX_NAME_LENGTH} characters`;
|
|
17
|
+
if (!SKILL_NAME_RE.test(name))
|
|
18
|
+
return "name must contain only lowercase letters, digits, and hyphens";
|
|
19
|
+
if (name.startsWith("-") || name.endsWith("-"))
|
|
20
|
+
return "name must not start or end with a hyphen";
|
|
21
|
+
if (name.includes("--")) return "name must not contain consecutive hyphens";
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
function createTokenFieldSchema(fieldName, example) {
|
|
25
|
+
return z.string({
|
|
26
|
+
error: `Frontmatter field "${fieldName}" must be a string when present`
|
|
27
|
+
}).superRefine((value, ctx) => {
|
|
28
|
+
const tokens = value.split(/\s+/).map((token) => token.trim()).filter((token) => token.length > 0);
|
|
29
|
+
for (const token of tokens) {
|
|
30
|
+
if (!CAPABILITY_TOKEN_RE.test(token)) {
|
|
31
|
+
ctx.addIssue({
|
|
32
|
+
code: z.ZodIssueCode.custom,
|
|
33
|
+
message: `${fieldName} token "${token}" is invalid; expected dotted lowercase tokens (for example "${example}")`
|
|
34
|
+
});
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function parseTokenList(value) {
|
|
41
|
+
if (typeof value !== "string") {
|
|
42
|
+
return void 0;
|
|
43
|
+
}
|
|
44
|
+
const tokens = value.split(/\s+/).map((token) => token.trim()).filter((token) => token.length > 0);
|
|
45
|
+
return tokens.length > 0 ? tokens : void 0;
|
|
46
|
+
}
|
|
47
|
+
var skillFrontmatterSchema = z.object({
|
|
48
|
+
name: z.string({ error: 'Frontmatter field "name" must be a string' }).superRefine((value, ctx) => {
|
|
49
|
+
const nameError = validateSkillName(value);
|
|
50
|
+
if (nameError) {
|
|
51
|
+
ctx.addIssue({
|
|
52
|
+
code: z.ZodIssueCode.custom,
|
|
53
|
+
message: nameError
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}),
|
|
57
|
+
description: z.string({ error: 'Frontmatter field "description" must be a string' }).superRefine((value, ctx) => {
|
|
58
|
+
if (!value.trim()) {
|
|
59
|
+
ctx.addIssue({
|
|
60
|
+
code: z.ZodIssueCode.custom,
|
|
61
|
+
message: "description must not be empty"
|
|
62
|
+
});
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (value.length > MAX_DESCRIPTION_LENGTH) {
|
|
66
|
+
ctx.addIssue({
|
|
67
|
+
code: z.ZodIssueCode.custom,
|
|
68
|
+
message: `description must be <= ${MAX_DESCRIPTION_LENGTH} characters`
|
|
69
|
+
});
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (hasAngleBrackets(value)) {
|
|
73
|
+
ctx.addIssue({
|
|
74
|
+
code: z.ZodIssueCode.custom,
|
|
75
|
+
message: 'description must not contain "<" or ">"'
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}),
|
|
79
|
+
metadata: z.record(z.string(), z.unknown(), {
|
|
80
|
+
error: 'Frontmatter field "metadata" must be an object when present'
|
|
81
|
+
}).optional(),
|
|
82
|
+
compatibility: z.string({
|
|
83
|
+
error: 'Frontmatter field "compatibility" must be a string when present'
|
|
84
|
+
}).superRefine((value, ctx) => {
|
|
85
|
+
if (value.length > MAX_COMPATIBILITY_LENGTH) {
|
|
86
|
+
ctx.addIssue({
|
|
87
|
+
code: z.ZodIssueCode.custom,
|
|
88
|
+
message: `compatibility must be <= ${MAX_COMPATIBILITY_LENGTH} characters`
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}).optional(),
|
|
92
|
+
license: z.string({
|
|
93
|
+
error: 'Frontmatter field "license" must be a string when present'
|
|
94
|
+
}).optional(),
|
|
95
|
+
"allowed-tools": z.string({
|
|
96
|
+
error: 'Frontmatter field "allowed-tools" must be a string when present'
|
|
97
|
+
}).optional(),
|
|
98
|
+
"requires-capabilities": createTokenFieldSchema(
|
|
99
|
+
"requires-capabilities",
|
|
100
|
+
"github.issues.write"
|
|
101
|
+
).optional(),
|
|
102
|
+
"uses-config": createTokenFieldSchema(
|
|
103
|
+
"uses-config",
|
|
104
|
+
"github.repo"
|
|
105
|
+
).optional()
|
|
106
|
+
}).passthrough();
|
|
107
|
+
function stripFrontmatter(raw) {
|
|
108
|
+
return raw.replace(FRONTMATTER_RE, "").trim();
|
|
109
|
+
}
|
|
110
|
+
function parseSkillFile(raw, expectedName) {
|
|
111
|
+
const match = FRONTMATTER_RE.exec(raw);
|
|
112
|
+
if (!match) {
|
|
113
|
+
return { ok: false, error: "Missing YAML frontmatter at start of file" };
|
|
114
|
+
}
|
|
115
|
+
let parsed;
|
|
116
|
+
try {
|
|
117
|
+
parsed = parseYaml(match[1]);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
return {
|
|
120
|
+
ok: false,
|
|
121
|
+
error: `Invalid YAML frontmatter: ${error instanceof Error ? error.message : String(error)}`
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
125
|
+
return { ok: false, error: "Frontmatter must be a YAML object" };
|
|
126
|
+
}
|
|
127
|
+
const result = skillFrontmatterSchema.safeParse(parsed);
|
|
128
|
+
if (!result.success) {
|
|
129
|
+
return {
|
|
130
|
+
ok: false,
|
|
131
|
+
error: result.error.issues[0]?.message ?? "Invalid YAML frontmatter"
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if (expectedName && result.data.name !== expectedName) {
|
|
135
|
+
return {
|
|
136
|
+
ok: false,
|
|
137
|
+
error: `name "${result.data.name}" must match directory "${expectedName}"`
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
const allowedTools = parseTokenList(result.data["allowed-tools"]);
|
|
141
|
+
const requiresCapabilities = parseTokenList(
|
|
142
|
+
result.data["requires-capabilities"]
|
|
143
|
+
);
|
|
144
|
+
const usesConfig = parseTokenList(result.data["uses-config"]);
|
|
145
|
+
return {
|
|
146
|
+
ok: true,
|
|
147
|
+
skill: {
|
|
148
|
+
name: result.data.name,
|
|
149
|
+
description: result.data.description,
|
|
150
|
+
body: stripFrontmatter(raw),
|
|
151
|
+
...result.data.metadata ? { metadata: result.data.metadata } : {},
|
|
152
|
+
...result.data.compatibility !== void 0 ? { compatibility: result.data.compatibility } : {},
|
|
153
|
+
...result.data.license !== void 0 ? { license: result.data.license } : {},
|
|
154
|
+
...allowedTools ? { allowedTools } : {},
|
|
155
|
+
...requiresCapabilities ? { requiresCapabilities } : {},
|
|
156
|
+
...usesConfig ? { usesConfig } : {}
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export {
|
|
162
|
+
stripFrontmatter,
|
|
163
|
+
parseSkillFile
|
|
164
|
+
};
|