skillgauntlet 1.0.0 → 1.1.1
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/LICENSE +201 -0
- package/LICENSE-DATA +438 -0
- package/README.md +238 -0
- package/bin/skillgauntlet.js +487 -0
- package/contracts/diagnosing-bugs.json +37 -0
- package/contracts/tdd.json +33 -0
- package/contracts/webapp-testing.json +38 -0
- package/contracts/xlsx.json +33 -0
- package/lib/codewhale.js +174 -0
- package/lib/codex.js +318 -0
- package/lib/depth.js +55 -0
- package/lib/discover.js +83 -0
- package/lib/execute.js +153 -0
- package/lib/gain.js +181 -0
- package/lib/i18n.js +767 -0
- package/lib/installed.js +43 -0
- package/lib/queries.js +37 -0
- package/lib/report.js +145 -0
- package/lib/runs.js +167 -0
- package/lib/spawn.js +84 -0
- package/lib/static.js +187 -0
- package/lib/trial.js +455 -0
- package/lib/ui.js +156 -0
- package/package.json +40 -6
- package/index.js +0 -1
package/lib/i18n.js
ADDED
|
@@ -0,0 +1,767 @@
|
|
|
1
|
+
// Three languages (zh, ja, en), chosen before anything else. Keys are shared across all three and
|
|
2
|
+
// tests/i18n.test.mjs keeps them identical; the CLI never hardcodes a user-facing string.
|
|
3
|
+
const MESSAGES = {
|
|
4
|
+
zh: {
|
|
5
|
+
langTitle: '语言 / Language',
|
|
6
|
+
langZh: '中文',
|
|
7
|
+
langEn: 'English',
|
|
8
|
+
langJa: '日本語',
|
|
9
|
+
title: 'SkillGauntlet — 装之前查',
|
|
10
|
+
rule: '────────────────────────',
|
|
11
|
+
sourceQ: '要测的技能装在哪?',
|
|
12
|
+
srcInstalled: '已安装(自动发现)',
|
|
13
|
+
srcInstalledHint: '扫 .agents/skills、.claude/skills、.codex/skills',
|
|
14
|
+
srcPath: '另一个本地目录',
|
|
15
|
+
srcRepo: 'GitHub 仓库(未安装)',
|
|
16
|
+
noInstalled: '本机没有找到已安装的技能。',
|
|
17
|
+
foundInstalled: '找到 {n} 个已安装的技能。',
|
|
18
|
+
scopeQ: '测哪些?',
|
|
19
|
+
scopeAll: '全测',
|
|
20
|
+
scopeAllHint: '{n} 个,一个一个跑',
|
|
21
|
+
scopeOne: '只测一个',
|
|
22
|
+
scopeOneHint: '方向键选择',
|
|
23
|
+
pickOneQ: '用 ↑ ↓ 选,回车确认',
|
|
24
|
+
askRepo: '输入技能来源(owner/repo,或 owner/repo/技能名)',
|
|
25
|
+
needRepo: '需要 owner/repo 形式,例如 mattpocock/skills',
|
|
26
|
+
noSkill: '这个地址里没有找到 SKILL.md。',
|
|
27
|
+
multiFound: '找到 {n} 个技能,请用 owner/repo/技能名 指定一个。',
|
|
28
|
+
notFoundNamed: '没找到名为 {name} 的技能。可选:{list}',
|
|
29
|
+
|
|
30
|
+
hostQ: '在哪个宿主里测?',
|
|
31
|
+
hostClaude: 'Claude Code',
|
|
32
|
+
hostClaudeHint: '能测触发率',
|
|
33
|
+
hostCodebuddy: 'CodeBuddy Code',
|
|
34
|
+
hostCodebuddyHint: '能测触发率(WorkBuddy 背后的命令行)',
|
|
35
|
+
codebuddyNote: 'CodeBuddy Code 的技能调用在事件流里与 Claude Code 同形(名为 Skill 的 tool_use)。用它自己的账号额度,需先在命令行里 /login;本宿主只做触发层,不做增益层。模型栏留空用 CodeBuddy 账号的默认模型;填 deepseek-flash 则走 DeepSeek(DEEPSEEK_API_KEY)。',
|
|
36
|
+
needDeepseekKey: '要用 DeepSeek 模型,请先在环境变量里设 DEEPSEEK_API_KEY(只放变量,不要把密钥写进命令行或文件)。',
|
|
37
|
+
codebuddyEstimate: '{skills} 个技能 × 约 {trials} 次试跑(含出题 1 次),用 CodeBuddy 账号额度,无现金花费。',
|
|
38
|
+
hostCodewhale: 'Codewhale',
|
|
39
|
+
hostCodewhaleHint: '能测触发率(原 DeepSeek-TUI,用 DeepSeek 模型)',
|
|
40
|
+
codewhaleNote: 'Codewhale 的技能调用在事件流里是名为 load_skill 的工具调用:第一个 input.name 等于被测技能才算触发(查询和列目录不算)。试跑在一个只装了被测技能的临时 HOME 里进行,只开放 load_skill 这一个工具;用 DEEPSEEK_API_KEY,花 DeepSeek 现金。这是 Codewhale 的数字,不与其他宿主的合并比较。需要 codewhale 在 PATH 里(官方发布页的单文件 exe,改名 codewhale.exe)。',
|
|
41
|
+
codewhaleEstimate: '{skills} 个技能 × 约 {trials} 次试跑(含出题 1 次),花 DeepSeek 现金,每次约几分钱。',
|
|
42
|
+
hostCodex: 'Codex',
|
|
43
|
+
hostCodexHint: '触发不可观测:只测静态与激活探针',
|
|
44
|
+
codexNote: 'Codex 把技能当作宿主侧上下文注入,事件流里没有"技能被调用"这一项(只有 command_execution / file_change / mcp_tool_call 等)。所以这里不给触发率——给了就是编的。替代方案是激活探针:同一请求装与不装各跑一次,比首个动作与改动文件。',
|
|
45
|
+
probeQ: '跑激活探针?(2 次运行)',
|
|
46
|
+
probeRun: '探针运行中(先装,再不装)…',
|
|
47
|
+
probeEmpty: 'Codex 没有返回任何事件:检查它是否已登录、`codex exec --json` 是否写到 stdout。',
|
|
48
|
+
probeTitle: '激活探针(装 / 不装)',
|
|
49
|
+
probeIntro: '同一请求跑两遍。首个动作或改动文件不同,说明技能产生了可观察的影响;完全相同说明没有。这不是触发率。',
|
|
50
|
+
probeWith: '装了技能',
|
|
51
|
+
probeWithout: '不装技能',
|
|
52
|
+
probeAction: '首个动作',
|
|
53
|
+
probeFiles: '改动文件',
|
|
54
|
+
probeSame: '相同',
|
|
55
|
+
probeDiffer: '不同',
|
|
56
|
+
probeActionKind: '首个动作类型',
|
|
57
|
+
probeArtifacts: '产出的文件',
|
|
58
|
+
probeNoVerdict: '这里只并列两次运行的事实,不给"有没有影响"的自动判定:同一请求两次运行的命令行字符串从不一样,"动作不同"几乎永远成立,据此下结论等于抛硬币。',
|
|
59
|
+
probeNoTrigger: '本宿主没有触发率数字,这是结构性的:Codex 不把技能调用暴露成事件。',
|
|
60
|
+
codexEstimate: 'Codex 只用你已登录的额度:{skills} 个技能 × {runs} 次运行,现金成本取决于你的 Codex 计划。',
|
|
61
|
+
codexStaticOnly: '只跑静态层:{skills} 个技能,不产生任何模型调用。',
|
|
62
|
+
|
|
63
|
+
depthQ: '测到什么程度?',
|
|
64
|
+
depthQuick: '快速',
|
|
65
|
+
depthQuickHint: '~1 分钟 · 只回答"能不能装上"',
|
|
66
|
+
depthStandard: '标准',
|
|
67
|
+
depthStandardHint: '~5 分钟 · 触发率有置信区间',
|
|
68
|
+
depthDeep: '深度',
|
|
69
|
+
depthDeepHint: '~10 分钟 · 加只读探索与配对增益',
|
|
70
|
+
providerQ: '用哪个后端?',
|
|
71
|
+
provClaude: 'Claude Code 订阅',
|
|
72
|
+
provClaudeHint: '不花现金,占周额度',
|
|
73
|
+
provDeepseek: 'DeepSeek',
|
|
74
|
+
provDeepseekHint: '花现金很少,不占订阅额度',
|
|
75
|
+
provManual: '手动输入模型名',
|
|
76
|
+
modelQ: '模型',
|
|
77
|
+
modelCheap: '最省',
|
|
78
|
+
modelDaily: '最贴近日常',
|
|
79
|
+
modelExpensive: '最贵',
|
|
80
|
+
needBaseUrl: '需要先设置后端:\n ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic\n ANTHROPIC_AUTH_TOKEN=<你的 key>',
|
|
81
|
+
backendLine: '后端:{backend} 模型:{model}',
|
|
82
|
+
estimate: '即将运行:{skills} 个技能 × {trials} 次试跑 ≈ 每个 {minutes} 分钟,合计约 {totalMinutes} 分钟\n费用取决于后端和计划:订阅走额度,DeepSeek 按量计费(这里不估金额)',
|
|
83
|
+
confirmRun: '继续?',
|
|
84
|
+
cancelled: '已取消。免费的静态层不需要确认:npx skillgauntlet static <目录>',
|
|
85
|
+
staticDone: '静态层:{verdicts}',
|
|
86
|
+
drafting: '正在出题(一次模型调用)…',
|
|
87
|
+
drafted: '出了 {q} 道题,{c} 条触发条款(已缓存,下次直接复用)',
|
|
88
|
+
queriesReused: '复用缓存的 {n} 道题({file}),省一次出题调用',
|
|
89
|
+
negativesChecked: '{n} 条负样本都填出了可核实的借用词',
|
|
90
|
+
weakNegatives: '警告:{total} 条负样本里有 {weak} 条没填出可核实的借用词,它们离描述太远,误报率会被低估',
|
|
91
|
+
trialFail: '触发层失败:{err}',
|
|
92
|
+
gainSkip: '增益层:跳过({reason})',
|
|
93
|
+
gainNote: '增益结果是本地对照,永不上传。',
|
|
94
|
+
reportAt: '报告:{path}',
|
|
95
|
+
runSaved: '本次运行已存档:{path}(raw.jsonl 逐条记录 · meta.json 运行条件 · summary.json 汇总)',
|
|
96
|
+
runStopped: '连续 {n} 次试跑出错或超时,已自动停止({reason})。多半是用量上限、令牌失效或网络中断;已完成的记录都保留,不写汇总。',
|
|
97
|
+
runIncomplete: '有 {n} 次试跑出错或超时、没有补上,汇总只覆盖了其余的试跑。',
|
|
98
|
+
resumeWith: '续跑(跳过已完成的,重试出错和超时的):{cmd}',
|
|
99
|
+
resumeNothing: '这次运行已经没有待跑的试跑,无需续跑。',
|
|
100
|
+
resumeDone: '续跑完成,本次补跑 {n} 次。',
|
|
101
|
+
resumeMismatch: '不能续跑:{what} 原来是 {was},现在是 {got}。不同条件的记录不能合并,请改回原值,或另开一次新运行。',
|
|
102
|
+
resumeQueriesChanged: '不能续跑:题集和这次运行用的不一致(题集文件被改过或丢失)。',
|
|
103
|
+
resumeSkillChanged: '不能续跑:SKILL.md 在这次运行开始后被改过。',
|
|
104
|
+
shareState: '公开榜单还没上线,所以这里不问你要不要上传、也不上传任何东西。上面那个目录就是将来要提交的格式——榜单开了可以直接交,不用重跑。',
|
|
105
|
+
inputEnded: '输入结束',
|
|
106
|
+
err: '出错:{msg}',
|
|
107
|
+
badSource: '看不懂这个地址:{spec}(可以是本地目录,或 owner/repo)',
|
|
108
|
+
noSkillUnder: '{target} 下没有找到 SKILL.md',
|
|
109
|
+
resumeUsage: '用法:skillgauntlet resume <运行目录> [--model M] [--runs N] [--max-explore N]',
|
|
110
|
+
'ui.yesWords': 'y,yes,是',
|
|
111
|
+
'ui.noWords': 'n,no,否',
|
|
112
|
+
usage: `SkillGauntlet
|
|
113
|
+
|
|
114
|
+
npx skillgauntlet 交互式
|
|
115
|
+
npx skillgauntlet static <目录> 只跑层 0,不调用模型
|
|
116
|
+
npx skillgauntlet static <目录> --json
|
|
117
|
+
npx skillgauntlet resume <运行目录> 续跑被中断或自动停止的运行(出错和超时的会重试)
|
|
118
|
+
加 --lang zh|ja|en 或设置 SG_LANG 可指定语言
|
|
119
|
+
|
|
120
|
+
层
|
|
121
|
+
0 静态 上下文成本、权限面、代码风险、指令劫持、描述质量 免费
|
|
122
|
+
1 触发 该触发时会不会触发,不该触发时会不会安静 调用模型
|
|
123
|
+
2 增益 装与不装对比,任务由程序判定 调用模型
|
|
124
|
+
|
|
125
|
+
层 0 总是最先跑:它免费,能在你花钱之前筛掉大部分问题。`,
|
|
126
|
+
modelRemap: '后端 {host} 会静默改写 Anthropic 模型名,"{model}" 测的不是你指定的模型;请传该后端自己的模型名',
|
|
127
|
+
hostMissing: '没有找到宿主 {host}(PATH 里没有 {bin})。{how};也可以重新运行并选择其他宿主(Claude Code、CodeBuddy、Codewhale、Codex)。',
|
|
128
|
+
installCodebuddy: '安装方法:npm install -g @tencent-ai/codebuddy-code',
|
|
129
|
+
installCodewhale: '安装方法:从官方发布页下载单文件 exe,改名为 codewhale.exe 并放进 PATH',
|
|
130
|
+
installClaude: '安装方法:npm install -g @anthropic-ai/claude-code',
|
|
131
|
+
|
|
132
|
+
// ---- report: shared ----
|
|
133
|
+
'report.path': '路径:',
|
|
134
|
+
'report.skillMd': 'SKILL.md:{chars} 字符 ≈ {tokens} tokens;description {desc} 字符',
|
|
135
|
+
'report.package': '包:{files} 个文件,其中 {code} 个可执行,共 {size}',
|
|
136
|
+
'report.permissions': '权限声明:{tools}',
|
|
137
|
+
'report.notDeclared': '未声明',
|
|
138
|
+
'report.groupHeader': '组',
|
|
139
|
+
'report.verdictHeader': '结论',
|
|
140
|
+
'report.checkHeader': '检查项',
|
|
141
|
+
'report.allPass': '全部通过',
|
|
142
|
+
'report.noComposite': '> 本页只报事实与标记,不给加权总分:加权分无法审计、无法申诉。',
|
|
143
|
+
'report.legend': '✓ 通过 ! 警告 ✗ 失败 · 仅信息(可能是特性,不是缺陷)',
|
|
144
|
+
'report.colon': ':',
|
|
145
|
+
|
|
146
|
+
// ---- report: groups ----
|
|
147
|
+
'group.A': '上下文成本',
|
|
148
|
+
'group.B': '权限面',
|
|
149
|
+
'group.C': '代码风险',
|
|
150
|
+
'group.D': '指令劫持',
|
|
151
|
+
'group.E': '描述质量',
|
|
152
|
+
|
|
153
|
+
// ---- report: checks ----
|
|
154
|
+
'check.A1.title': 'SKILL.md 体量',
|
|
155
|
+
'check.A1.detail': '{chars} 字符 ≈ {tokens} tokens',
|
|
156
|
+
'check.A1.heavy': '{chars} 字符 ≈ {tokens} tokens(触发后整段进上下文)',
|
|
157
|
+
'check.A2.title': 'description 长度',
|
|
158
|
+
'check.A2.detail': '{chars} 字符(宿主每次请求都只读这一段,长度直接决定误触发面)',
|
|
159
|
+
'check.A2.missing': '没有 description,宿主无法匹配',
|
|
160
|
+
'check.A3.title': '渐进披露',
|
|
161
|
+
'check.A3.detail': '正文引用了 {n} 处外部文件,可以按需加载',
|
|
162
|
+
'check.A3.none': '正文没有引用外部文件,全部内容一次性进入上下文',
|
|
163
|
+
'check.A4.title': '包体量',
|
|
164
|
+
'check.A4.detail': '{size} / {files} 个文件',
|
|
165
|
+
'check.B1.title': '是否声明 allowed-tools',
|
|
166
|
+
'check.B1.declared': '声明为:{tools}',
|
|
167
|
+
'check.B1.missing': '没有声明权限范围,宿主要按默认策略给',
|
|
168
|
+
'check.B2.title': '声明范围宽度',
|
|
169
|
+
'check.B2.wide': '声明了无限制的写/执行权限',
|
|
170
|
+
'check.B2.narrow': '声明范围有限',
|
|
171
|
+
'check.B3.title': '能否自动调用',
|
|
172
|
+
'check.B3.manual': '声明了 disable-model-invocation,只能手动调用(不会自动触发)',
|
|
173
|
+
'check.B3.auto': '允许模型自动调用',
|
|
174
|
+
'check.B4.title': '随包代码',
|
|
175
|
+
'check.B4.detail': '{n} 个可执行文件:{list}',
|
|
176
|
+
'check.B4.none': '纯文档,没有可执行文件',
|
|
177
|
+
'check.C1.title': '网络调用',
|
|
178
|
+
'check.C2.title': '命令执行 / 动态求值',
|
|
179
|
+
'check.C3.title': '凭证或环境变量访问',
|
|
180
|
+
'check.C4.title': '混淆迹象',
|
|
181
|
+
'check.C5.title': '安装钩子',
|
|
182
|
+
'check.C.none': '未发现',
|
|
183
|
+
'check.C.hits': '{n} 处以上',
|
|
184
|
+
'check.C.escalated': '{n} 处以上,且未声明权限范围',
|
|
185
|
+
'check.D1.title': '覆盖指令',
|
|
186
|
+
'check.D1.hit': '正文出现"忽略之前的指令"类模式',
|
|
187
|
+
'check.D2.title': '要求敏感路径',
|
|
188
|
+
'check.D2.hit': '正文要求访问凭证或环境变量',
|
|
189
|
+
'check.D3.title': '要求外发数据',
|
|
190
|
+
'check.D3.hit': '"发送/上传 到 URL" 类措辞,请人工确认',
|
|
191
|
+
'check.D4.title': '隐藏字符',
|
|
192
|
+
'check.D4.hit': '含零宽/双向控制字符,源码里看不见',
|
|
193
|
+
'check.D5.title': '外部图片',
|
|
194
|
+
'check.D5.hit': '引用外部图片,加载即向第三方发出请求',
|
|
195
|
+
'check.D.none': '未发现',
|
|
196
|
+
'check.E1.title': 'description 是否存在',
|
|
197
|
+
'check.E1.detail': '{chars} 字符',
|
|
198
|
+
'check.E1.missing': '缺失',
|
|
199
|
+
'check.E2.title': '是否说明何时使用',
|
|
200
|
+
'check.E2.hit': '含触发条件措辞',
|
|
201
|
+
'check.E2.miss': '没有"何时使用"的表述,模型只能靠语义硬猜',
|
|
202
|
+
'check.E3.title': '是否过宽',
|
|
203
|
+
'check.E3.hit': '出现"任何/所有/any"类全称量词,误触发面大',
|
|
204
|
+
'check.E3.none': '未发现全称量词',
|
|
205
|
+
'check.E4.title': '触发条款数(粗估)',
|
|
206
|
+
'check.E4.detail': '约 {n} 条(按分隔符粗估,出题时以模型判定的条款清单为准)',
|
|
207
|
+
'check.E5.title': '名字与目录是否一致',
|
|
208
|
+
'check.E5.detail': 'frontmatter name = {name},目录 = {dir}',
|
|
209
|
+
'check.E5.noname': '没有 name 字段',
|
|
210
|
+
|
|
211
|
+
// ---- report: trigger ----
|
|
212
|
+
'poll.title': '你主要用哪个宿主?',
|
|
213
|
+
'poll.body': '1) Claude Code 2) Codex 3) 其他 —— 回一个数字就行。',
|
|
214
|
+
'poll.why': '为什么问:触发率只在支持显式技能调用的宿主上可测。Codex 的事件流里没有 skill item,那一列是空的,不是没测。所以读者用什么宿主,决定这份报告对谁有用、下一步该补哪一层。答案只用作信号,不做比例统计:回帖的人是自我选择的,算不出比例。',
|
|
215
|
+
'trial.title': '触发率',
|
|
216
|
+
'trial.modelLine': '模型:{model}({backend});宿主:{host};每题 {runs} 轮,共 {trials} 次试跑',
|
|
217
|
+
'trial.hostUnknown': '未记录',
|
|
218
|
+
'trial.recall': '召回率:{p}(95% CI {lo}–{hi})',
|
|
219
|
+
'trial.fpr': '误报率:{p}(95% CI {lo}–{hi})',
|
|
220
|
+
'trial.noTool': '应触发题上"完全没调用任何工具":{p}',
|
|
221
|
+
'trial.noToolWarn': ' ← 这通常是模型或宿主的问题,不是描述的问题',
|
|
222
|
+
'trial.stateHeader': '状态',
|
|
223
|
+
'trial.queryHeader': '题',
|
|
224
|
+
'trial.hitsHeader': '命中',
|
|
225
|
+
'trial.should': '应触发',
|
|
226
|
+
'trial.shouldNot': '不应触发',
|
|
227
|
+
|
|
228
|
+
// ---- report: gain ----
|
|
229
|
+
'gain.title': '增益:装了与不装的对照(本地结果,永不上传)',
|
|
230
|
+
'gain.intro': '同一批任务跑两遍——一遍带着这个技能,一遍不带——再看哪些"代码能判定"的契约被满足。',
|
|
231
|
+
'gain.local': '这是给你自己看的对照,不是分数;内容不会上传,也不进榜单。',
|
|
232
|
+
'gain.contractHeader': '契约',
|
|
233
|
+
'gain.withHeader': '装了',
|
|
234
|
+
'gain.withoutHeader': '不装',
|
|
235
|
+
'gain.dirHeader': '方向',
|
|
236
|
+
'gain.up': '↑ 提升',
|
|
237
|
+
'gain.down': '↓ 下降',
|
|
238
|
+
'gain.same': '= 无差别',
|
|
239
|
+
'gain.perTask': '逐个任务看开关前后的差别',
|
|
240
|
+
'gain.withSkill': '装着技能',
|
|
241
|
+
'gain.withoutSkill': '不装技能',
|
|
242
|
+
'gain.noFiles': '没有新增文件',
|
|
243
|
+
'gain.side': '新增 {files} 契约 {ok}/{n}',
|
|
244
|
+
'gain.footnote1': '> 只有契约文件里写明、且能被程序判定的效果才在这里。审美类或开放式任务不在其中——',
|
|
245
|
+
'gain.footnote2': '> 用 LLM 当裁判能覆盖它们,但那样的分数不可复现,也不可申诉。',
|
|
246
|
+
'gain.noContracts': '这个技能还没有契约文件,无法用确定性断言判定效果',
|
|
247
|
+
},
|
|
248
|
+
en: {
|
|
249
|
+
langTitle: 'Language / 语言',
|
|
250
|
+
langZh: '中文',
|
|
251
|
+
langEn: 'English',
|
|
252
|
+
langJa: '日本語',
|
|
253
|
+
title: 'SkillGauntlet — check before you install',
|
|
254
|
+
rule: '────────────────────────',
|
|
255
|
+
sourceQ: 'Where is the skill?',
|
|
256
|
+
srcInstalled: 'Already installed (auto-discovered)',
|
|
257
|
+
srcInstalledHint: 'scans .agents/skills, .claude/skills, .codex/skills',
|
|
258
|
+
srcPath: 'Another local directory',
|
|
259
|
+
srcRepo: 'GitHub repository (not installed)',
|
|
260
|
+
noInstalled: 'No installed skills found on this machine.',
|
|
261
|
+
foundInstalled: 'Found {n} installed skills.',
|
|
262
|
+
scopeQ: 'Which ones?',
|
|
263
|
+
scopeAll: 'All of them',
|
|
264
|
+
scopeAllHint: '{n} skills, one after another',
|
|
265
|
+
scopeOne: 'Just one',
|
|
266
|
+
scopeOneHint: 'pick with arrow keys',
|
|
267
|
+
pickOneQ: '↑ ↓ to move, enter to confirm',
|
|
268
|
+
askRepo: 'Source of the skill (owner/repo, or owner/repo/skill-name)',
|
|
269
|
+
needRepo: 'Expected owner/repo, e.g. mattpocock/skills',
|
|
270
|
+
noSkill: 'No SKILL.md found there.',
|
|
271
|
+
multiFound: 'Found {n} skills; name one with owner/repo/skill-name.',
|
|
272
|
+
notFoundNamed: 'No skill named {name}. Available: {list}',
|
|
273
|
+
|
|
274
|
+
hostQ: 'Which host?',
|
|
275
|
+
hostClaude: 'Claude Code',
|
|
276
|
+
hostClaudeHint: 'trigger rate is measurable',
|
|
277
|
+
hostCodebuddy: 'CodeBuddy Code',
|
|
278
|
+
hostCodebuddyHint: 'trigger rate is measurable (the CLI behind WorkBuddy)',
|
|
279
|
+
codebuddyNote: 'In CodeBuddy Code a skill call appears in the stream as a tool_use named Skill, the same shape as in Claude Code. It spends your CodeBuddy account quota and needs /login in its CLI first. This host runs the trigger layer only, not the gain layer. Leave the model empty for the account default, or type deepseek-flash to use DeepSeek (DEEPSEEK_API_KEY).',
|
|
280
|
+
needDeepseekKey: 'To use a DeepSeek model, set DEEPSEEK_API_KEY in the environment first (a variable only; keep the key out of the command line and files).',
|
|
281
|
+
codebuddyEstimate: '{skills} skill(s) x about {trials} trials (plus one drafting call), spent from the CodeBuddy account, no cash.',
|
|
282
|
+
hostCodewhale: 'Codewhale',
|
|
283
|
+
hostCodewhaleHint: 'trigger rate is measurable (formerly DeepSeek-TUI, runs DeepSeek models)',
|
|
284
|
+
codewhaleNote: 'In Codewhale a skill call is a tool call named load_skill: the first one whose input.name equals the tested skill counts as a trigger (a query or a catalogue listing does not). Trials run in a throw-away HOME holding only the tested skill, with load_skill as the only tool; it uses DEEPSEEK_API_KEY and spends DeepSeek cash. The number is a Codewhale number and is not merged with another host. It needs codewhale on PATH (the single exe from the official release page, renamed codewhale.exe).',
|
|
285
|
+
codewhaleEstimate: '{skills} skill(s) x about {trials} trials (plus one drafting call), DeepSeek cash, a few cents each.',
|
|
286
|
+
hostCodex: 'Codex',
|
|
287
|
+
hostCodexHint: 'trigger is not observable: static plus an activation probe',
|
|
288
|
+
codexNote: 'Codex injects a skill as host-side context; the event stream has no "skill was used" item (only command_execution, file_change, mcp_tool_call). A trigger rate here would have to be invented, so instead there is an activation probe: the same request with and without the skill, comparing the first action and the files changed.',
|
|
289
|
+
probeQ: 'Run the activation probe? (2 runs)',
|
|
290
|
+
probeRun: 'Probing (with the skill, then without)…',
|
|
291
|
+
probeEmpty: 'Codex returned no events: check that it is logged in and that `codex exec --json` writes JSONL to stdout.',
|
|
292
|
+
probeTitle: 'Activation probe (with / without)',
|
|
293
|
+
probeIntro: 'The same request, run twice. A different first action or a different set of changed files is evidence the skill had an observable effect; identical means it had none. This is not a trigger rate.',
|
|
294
|
+
probeWith: 'with the skill',
|
|
295
|
+
probeWithout: 'without it',
|
|
296
|
+
probeAction: 'first action',
|
|
297
|
+
probeFiles: 'changed files',
|
|
298
|
+
probeSame: 'same',
|
|
299
|
+
probeDiffer: 'differs',
|
|
300
|
+
probeActionKind: 'first action kind',
|
|
301
|
+
probeArtifacts: 'files produced',
|
|
302
|
+
probeNoVerdict: 'This lists the facts of two runs and gives no automatic influenced/not-influenced verdict: two runs of the same request never execute identical command strings, so "the action differs" is true almost always and would decide nothing.',
|
|
303
|
+
probeNoTrigger: 'There is no trigger number for this host, for a structural reason: Codex does not expose skill invocation as an event.',
|
|
304
|
+
codexEstimate: 'Codex spends only your logged-in quota: {skills} skill(s) × {runs} runs; cash cost depends on your Codex plan.',
|
|
305
|
+
codexStaticOnly: 'Static layer only: {skills} skill(s), no model calls at all.',
|
|
306
|
+
|
|
307
|
+
depthQ: 'How deep?',
|
|
308
|
+
depthQuick: 'Quick',
|
|
309
|
+
depthQuickHint: '~1 min · only answers "will it install"',
|
|
310
|
+
depthStandard: 'Standard',
|
|
311
|
+
depthStandardHint: '~5 min · trigger rate with intervals',
|
|
312
|
+
depthDeep: 'Deep',
|
|
313
|
+
depthDeepHint: '~10 min · adds read-only exploration and paired gain',
|
|
314
|
+
providerQ: 'Which backend?',
|
|
315
|
+
provClaude: 'Claude Code subscription',
|
|
316
|
+
provClaudeHint: 'no cash, spends weekly quota',
|
|
317
|
+
provDeepseek: 'DeepSeek',
|
|
318
|
+
provDeepseekHint: 'little cash, no quota',
|
|
319
|
+
provManual: 'Type a model name',
|
|
320
|
+
modelQ: 'Model',
|
|
321
|
+
modelCheap: 'cheapest',
|
|
322
|
+
modelDaily: 'closest to daily use',
|
|
323
|
+
modelExpensive: 'most expensive',
|
|
324
|
+
needBaseUrl: 'Set the backend first:\n ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic\n ANTHROPIC_AUTH_TOKEN=<your key>',
|
|
325
|
+
backendLine: 'Backend: {backend} model: {model}',
|
|
326
|
+
estimate: 'About to run: {skills} skill(s) × {trials} trials ≈ {minutes} min each, {totalMinutes} min in total\nCost depends on the backend and plan: a subscription spends quota, DeepSeek bills per use (no amount is estimated here)',
|
|
327
|
+
confirmRun: 'Continue?',
|
|
328
|
+
cancelled: 'Cancelled. The free static layer needs no confirmation: npx skillgauntlet static <dir>',
|
|
329
|
+
staticDone: 'Static: {verdicts}',
|
|
330
|
+
drafting: 'Drafting questions (one model call)…',
|
|
331
|
+
drafted: '{q} queries over {c} trigger clauses (cached for reuse)',
|
|
332
|
+
queriesReused: 'reusing {n} cached questions ({file}), one drafting call saved',
|
|
333
|
+
negativesChecked: 'all {n} negatives name verifiable borrowed wording',
|
|
334
|
+
weakNegatives: 'warning: {weak} of {total} negatives name no verifiable borrowed wording, so they sit too far from the description and will understate false positives',
|
|
335
|
+
trialFail: 'Trigger layer failed: {err}',
|
|
336
|
+
gainSkip: 'Gain layer skipped: {reason}',
|
|
337
|
+
gainNote: 'Gain results are a local comparison and are never uploaded.',
|
|
338
|
+
reportAt: 'Report: {path}',
|
|
339
|
+
runSaved: 'Run archived at {path} (raw.jsonl one record per trial, meta.json the conditions, summary.json the totals)',
|
|
340
|
+
runStopped: 'Stopped after {n} failed trials in a row ({reason}). Usually a usage limit, a dead token or a network outage. Finished records are kept; no summary is written.',
|
|
341
|
+
runIncomplete: '{n} trials errored or timed out and were not made up; the summary covers only the rest.',
|
|
342
|
+
resumeWith: 'Resume (finished trials are skipped, errors and timeouts are retried): {cmd}',
|
|
343
|
+
resumeNothing: 'This run has no trials left to do; nothing to resume.',
|
|
344
|
+
resumeDone: 'Resume finished; {n} trials ran.',
|
|
345
|
+
resumeMismatch: 'Cannot resume: {what} was {was}, now {got}. Records from different conditions cannot be pooled; use the original value or start a new run.',
|
|
346
|
+
resumeQueriesChanged: 'Cannot resume: the question set no longer matches the one this run used (the file was edited or is missing).',
|
|
347
|
+
resumeSkillChanged: 'Cannot resume: SKILL.md changed after this run started.',
|
|
348
|
+
shareState: 'There is no public leaderboard yet, so this asks nothing about uploading and uploads nothing. The directory above is the submission format: when the board opens it can be submitted as is, with no rerun.',
|
|
349
|
+
inputEnded: 'input ended',
|
|
350
|
+
err: 'Error: {msg}',
|
|
351
|
+
badSource: 'Cannot read this address: {spec} (use a local directory or owner/repo)',
|
|
352
|
+
noSkillUnder: 'no SKILL.md under {target}',
|
|
353
|
+
resumeUsage: 'usage: skillgauntlet resume <run-dir> [--model M] [--runs N] [--max-explore N]',
|
|
354
|
+
'ui.yesWords': 'y,yes',
|
|
355
|
+
'ui.noWords': 'n,no',
|
|
356
|
+
usage: `SkillGauntlet
|
|
357
|
+
|
|
358
|
+
npx skillgauntlet interactive
|
|
359
|
+
npx skillgauntlet static <dir> layer 0 only, no model calls
|
|
360
|
+
npx skillgauntlet static <dir> --json
|
|
361
|
+
npx skillgauntlet resume <run-dir> continue an interrupted or stopped run (errors and timeouts are retried)
|
|
362
|
+
add --lang zh|ja|en or set SG_LANG to choose the language
|
|
363
|
+
|
|
364
|
+
Layers
|
|
365
|
+
0 static context cost, permission surface, code risk, instruction hijacking, description free
|
|
366
|
+
1 trigger does it fire when it should, and stay quiet when it should not model calls
|
|
367
|
+
2 gain with the skill vs without it, on tasks a program can grade model calls
|
|
368
|
+
|
|
369
|
+
Layer 0 always runs first: it is free, and it disqualifies most problems before you pay.`,
|
|
370
|
+
modelRemap: 'backend {host} remaps Anthropic model names, so "{model}" would test a different model; pass that backend\'s own model id',
|
|
371
|
+
hostMissing: 'Host {host} was not found ({bin} is not on PATH). {how}, or run again and pick another host (Claude Code, CodeBuddy, Codewhale, Codex).',
|
|
372
|
+
installCodebuddy: 'To install: npm install -g @tencent-ai/codebuddy-code',
|
|
373
|
+
installCodewhale: 'To install: download the single exe from the official release page, rename it codewhale.exe and put it on PATH',
|
|
374
|
+
installClaude: 'To install: npm install -g @anthropic-ai/claude-code',
|
|
375
|
+
|
|
376
|
+
'report.path': 'Path: ',
|
|
377
|
+
'report.skillMd': 'SKILL.md: {chars} chars ≈ {tokens} tokens; description {desc} chars',
|
|
378
|
+
'report.package': 'Package: {files} files, {code} executable, {size}',
|
|
379
|
+
'report.permissions': 'Declared scope: {tools}',
|
|
380
|
+
'report.notDeclared': 'none',
|
|
381
|
+
'report.groupHeader': 'Group',
|
|
382
|
+
'report.verdictHeader': 'Verdict',
|
|
383
|
+
'report.checkHeader': 'Checks',
|
|
384
|
+
'report.allPass': 'all pass',
|
|
385
|
+
'report.noComposite': '> This page reports facts and flags and gives no weighted total: a weighted total cannot be audited or appealed.',
|
|
386
|
+
'report.legend': '✓ pass ! warning ✗ failure · information only (may be a feature, not a defect)',
|
|
387
|
+
'report.colon': ': ',
|
|
388
|
+
|
|
389
|
+
'group.A': 'Context cost',
|
|
390
|
+
'group.B': 'Permission surface',
|
|
391
|
+
'group.C': 'Code risk',
|
|
392
|
+
'group.D': 'Instruction hijacking',
|
|
393
|
+
'group.E': 'Description quality',
|
|
394
|
+
|
|
395
|
+
'check.A1.title': 'SKILL.md size',
|
|
396
|
+
'check.A1.detail': '{chars} chars ≈ {tokens} tokens',
|
|
397
|
+
'check.A1.heavy': '{chars} chars ≈ {tokens} tokens (the whole body enters the window on every trigger)',
|
|
398
|
+
'check.A2.title': 'description length',
|
|
399
|
+
'check.A2.detail': '{chars} chars (read on every request; its length sets the false-trigger surface)',
|
|
400
|
+
'check.A2.missing': 'no description, so the host cannot match it',
|
|
401
|
+
'check.A3.title': 'progressive disclosure',
|
|
402
|
+
'check.A3.detail': 'the body references {n} external files, so they load on demand',
|
|
403
|
+
'check.A3.none': 'the body references no external files, so everything enters the window at once',
|
|
404
|
+
'check.A4.title': 'package size',
|
|
405
|
+
'check.A4.detail': '{size} / {files} files',
|
|
406
|
+
'check.B1.title': 'allowed-tools declared',
|
|
407
|
+
'check.B1.declared': 'declared: {tools}',
|
|
408
|
+
'check.B1.missing': 'no scope declared; the host grants the default',
|
|
409
|
+
'check.B2.title': 'scope width',
|
|
410
|
+
'check.B2.wide': 'declares unlimited write/execute scope',
|
|
411
|
+
'check.B2.narrow': 'scope is bounded',
|
|
412
|
+
'check.B3.title': 'model invocation',
|
|
413
|
+
'check.B3.manual': 'disable-model-invocation is set: manual only, never triggered automatically',
|
|
414
|
+
'check.B3.auto': 'the model may invoke it',
|
|
415
|
+
'check.B4.title': 'shipped code',
|
|
416
|
+
'check.B4.detail': '{n} executable files: {list}',
|
|
417
|
+
'check.B4.none': 'text only, no executable files',
|
|
418
|
+
'check.C1.title': 'network calls',
|
|
419
|
+
'check.C2.title': 'command execution / eval',
|
|
420
|
+
'check.C3.title': 'credentials or env access',
|
|
421
|
+
'check.C4.title': 'obfuscation',
|
|
422
|
+
'check.C5.title': 'install hooks',
|
|
423
|
+
'check.C.none': 'none found',
|
|
424
|
+
'check.C.hits': '{n} or more',
|
|
425
|
+
'check.C.escalated': '{n} or more, and no scope declared',
|
|
426
|
+
'check.D1.title': 'override instructions',
|
|
427
|
+
'check.D1.hit': 'an "ignore previous instructions" pattern appears in the body',
|
|
428
|
+
'check.D2.title': 'asks for sensitive paths',
|
|
429
|
+
'check.D2.hit': 'the body asks for credentials or environment variables',
|
|
430
|
+
'check.D3.title': 'asks to send data out',
|
|
431
|
+
'check.D3.hit': '"send/upload to a URL" phrasing; confirm by hand',
|
|
432
|
+
'check.D4.title': 'hidden characters',
|
|
433
|
+
'check.D4.hit': 'zero-width or bidi control characters, invisible in source',
|
|
434
|
+
'check.D5.title': 'external images',
|
|
435
|
+
'check.D5.hit': 'references an external image: rendering it leaks a request',
|
|
436
|
+
'check.D.none': 'none found',
|
|
437
|
+
'check.E1.title': 'description present',
|
|
438
|
+
'check.E1.detail': '{chars} chars',
|
|
439
|
+
'check.E1.missing': 'missing',
|
|
440
|
+
'check.E2.title': 'states when to use it',
|
|
441
|
+
'check.E2.hit': 'trigger wording present',
|
|
442
|
+
'check.E2.miss': 'no "when to use" wording, so the model can only guess from semantics',
|
|
443
|
+
'check.E3.title': 'too broad',
|
|
444
|
+
'check.E3.hit': 'universal quantifiers ("any", "all") widen the false-trigger surface',
|
|
445
|
+
'check.E3.none': 'no universal quantifiers',
|
|
446
|
+
'check.E4.title': 'trigger clauses (rough)',
|
|
447
|
+
'check.E4.detail': 'about {n} (counted from separators; the drafted clause list is authoritative)',
|
|
448
|
+
'check.E5.title': 'name matches directory',
|
|
449
|
+
'check.E5.detail': 'frontmatter name = {name}, directory = {dir}',
|
|
450
|
+
'check.E5.noname': 'no name field',
|
|
451
|
+
|
|
452
|
+
'poll.title': 'Which host do you mainly use?',
|
|
453
|
+
'poll.body': '1) Claude Code 2) Codex 3) Other — reply with a single digit.',
|
|
454
|
+
'poll.why': 'Why ask: a trigger rate is only measurable on a host that exposes explicit skill invocation. Codex has no skill item in its event stream, so its column is empty rather than unmeasured. Which host a reader uses therefore decides who the report serves and which layer to build next. The answers are read as a signal, never as a proportion: whoever replies has selected themselves, so no ratio can be computed from it.',
|
|
455
|
+
'trial.title': 'Trigger rate',
|
|
456
|
+
'trial.modelLine': 'Model: {model} ({backend}); host: {host}; {runs} runs per query, {trials} trials',
|
|
457
|
+
'trial.hostUnknown': 'not recorded',
|
|
458
|
+
'trial.recall': 'Recall: {p} (95% CI {lo}–{hi})',
|
|
459
|
+
'trial.fpr': 'False positives: {p} (95% CI {lo}–{hi})',
|
|
460
|
+
'trial.noTool': 'Answered without calling any tool on should-trigger queries: {p}',
|
|
461
|
+
'trial.noToolWarn': ' ← usually the model or the harness, not the description',
|
|
462
|
+
'trial.stateHeader': 'State',
|
|
463
|
+
'trial.queryHeader': 'Query',
|
|
464
|
+
'trial.hitsHeader': 'Hits',
|
|
465
|
+
'trial.should': 'should trigger',
|
|
466
|
+
'trial.shouldNot': 'should not',
|
|
467
|
+
|
|
468
|
+
'gain.title': 'Gain: with the skill vs without it (local result, never uploaded)',
|
|
469
|
+
'gain.intro': 'The same tasks run twice — once with the skill, once without — then check which contracts a program can grade.',
|
|
470
|
+
'gain.local': 'This is a comparison for you, not a score; nothing here is uploaded or enters the leaderboard.',
|
|
471
|
+
'gain.contractHeader': 'Contract',
|
|
472
|
+
'gain.withHeader': 'with',
|
|
473
|
+
'gain.withoutHeader': 'without',
|
|
474
|
+
'gain.dirHeader': 'Direction',
|
|
475
|
+
'gain.up': '↑ improves',
|
|
476
|
+
'gain.down': '↓ degrades',
|
|
477
|
+
'gain.same': '= no difference',
|
|
478
|
+
'gain.perTask': 'Task by task, with the skill on and off',
|
|
479
|
+
'gain.withSkill': 'with the skill',
|
|
480
|
+
'gain.withoutSkill': 'without it',
|
|
481
|
+
'gain.noFiles': 'no new files',
|
|
482
|
+
'gain.side': 'added {files}; contracts {ok}/{n}',
|
|
483
|
+
'gain.footnote1': '> Only effects a contract states and a program can grade appear here. Aesthetic or open-ended',
|
|
484
|
+
'gain.footnote2': '> tasks are absent: an LLM judge could cover them, but its score is neither reproducible nor appealable.',
|
|
485
|
+
'gain.noContracts': 'no contract file for this skill, so no effect can be graded by assertion',
|
|
486
|
+
},
|
|
487
|
+
ja: {
|
|
488
|
+
langTitle: '言語 / Language',
|
|
489
|
+
langZh: '中文',
|
|
490
|
+
langEn: 'English',
|
|
491
|
+
langJa: '日本語',
|
|
492
|
+
title: 'SkillGauntlet — インストール前にチェック',
|
|
493
|
+
rule: '────────────────────────',
|
|
494
|
+
sourceQ: 'テストするスキルはどこにありますか?',
|
|
495
|
+
srcInstalled: 'インストール済み(自動検出)',
|
|
496
|
+
srcInstalledHint: '.agents/skills、.claude/skills、.codex/skills を走査',
|
|
497
|
+
srcPath: '別のローカルディレクトリ',
|
|
498
|
+
srcRepo: 'GitHub リポジトリ(未インストール)',
|
|
499
|
+
noInstalled: 'このマシンにインストール済みのスキルが見つかりません。',
|
|
500
|
+
foundInstalled: 'インストール済みのスキルが {n} 件見つかりました。',
|
|
501
|
+
scopeQ: 'どれをテストしますか?',
|
|
502
|
+
scopeAll: 'すべて',
|
|
503
|
+
scopeAllHint: '{n} 件を順番に実行',
|
|
504
|
+
scopeOne: '1 件だけ',
|
|
505
|
+
scopeOneHint: '矢印キーで選択',
|
|
506
|
+
pickOneQ: '↑ ↓ で選び、Enter で確定',
|
|
507
|
+
askRepo: 'スキルの取得元(owner/repo、または owner/repo/スキル名)',
|
|
508
|
+
needRepo: 'owner/repo の形式で入力してください(例:mattpocock/skills)',
|
|
509
|
+
noSkill: 'そのアドレスに SKILL.md が見つかりません。',
|
|
510
|
+
multiFound: 'スキルが {n} 件見つかりました。owner/repo/スキル名 で 1 件指定してください。',
|
|
511
|
+
notFoundNamed: '{name} というスキルは見つかりません。候補:{list}',
|
|
512
|
+
|
|
513
|
+
hostQ: 'どのホストでテストしますか?',
|
|
514
|
+
hostClaude: 'Claude Code',
|
|
515
|
+
hostClaudeHint: '発動率を測定できます',
|
|
516
|
+
hostCodex: 'Codex',
|
|
517
|
+
hostCodexHint: '発動は観測できません:静的チェックと有効化プローブのみ',
|
|
518
|
+
hostCodebuddy: 'CodeBuddy Code',
|
|
519
|
+
hostCodebuddyHint: '発動率を測定できます(WorkBuddy の背後にある CLI)',
|
|
520
|
+
codebuddyNote: 'CodeBuddy Code では、スキルの呼び出しはイベントストリームに Skill という名前の tool_use として現れ、Claude Code と同じ形です。CodeBuddy アカウントの利用枠を使うため、先に CLI で /login が必要です。このホストでは発動レイヤーのみを実行し、効果レイヤーは実行しません。モデル欄を空にするとアカウントの既定モデル、deepseek-flash と入力すると DeepSeek(DEEPSEEK_API_KEY)を使います。',
|
|
521
|
+
needDeepseekKey: 'DeepSeek のモデルを使うには、先に環境変数 DEEPSEEK_API_KEY を設定してください(変数にのみ置き、キーをコマンドラインやファイルに書かないでください)。',
|
|
522
|
+
codebuddyEstimate: '{skills} 個のスキル × 約 {trials} 回の試行(質問作成 1 回を含む)。CodeBuddy アカウントの利用枠を使い、現金はかかりません。',
|
|
523
|
+
hostCodewhale: 'Codewhale',
|
|
524
|
+
hostCodewhaleHint: '発動率を測定できます(旧 DeepSeek-TUI、DeepSeek のモデルで動作)',
|
|
525
|
+
codewhaleNote: 'Codewhale では、スキルの呼び出しは load_skill という名前のツール呼び出しです。最初の呼び出しの input.name が対象スキルと一致した場合のみ発動とみなします(検索や一覧表示は含みません)。試行は対象スキルだけを入れた使い捨ての HOME で行い、使えるツールは load_skill のみです。DEEPSEEK_API_KEY を使い、DeepSeek の現金がかかります。これは Codewhale の数値であり、他のホストの数値とは合算・比較しません。codewhale が PATH 上に必要です(公式リリースページの単体 exe を codewhale.exe に改名)。',
|
|
526
|
+
codewhaleEstimate: '{skills} 個のスキル × 約 {trials} 回の試行(質問作成 1 回を含む)。DeepSeek の現金がかかり、1 回あたり数セント程度です。',
|
|
527
|
+
codexNote: 'Codex はスキルをホスト側のコンテキストとして注入するため、イベントストリームに「スキルが使われた」という項目がありません(command_execution / file_change / mcp_tool_call などのみ)。ここで発動率を出すと作り話になるので出しません。代わりに有効化プローブを使います:同じリクエストをスキルあり・なしで 1 回ずつ実行し、最初の動作と変更されたファイルを比べます。',
|
|
528
|
+
probeQ: '有効化プローブを実行しますか?(2 回実行)',
|
|
529
|
+
probeRun: 'プローブ実行中(スキルあり、次にスキルなし)…',
|
|
530
|
+
probeEmpty: 'Codex からイベントが返りませんでした。ログイン済みか、`codex exec --json` が stdout に出力しているかを確認してください。',
|
|
531
|
+
probeTitle: '有効化プローブ(あり / なし)',
|
|
532
|
+
probeIntro: '同じリクエストを 2 回実行します。最初の動作や変更ファイルが異なれば、スキルが観測可能な影響を与えた証拠です。完全に同じなら影響はありません。これは発動率ではありません。',
|
|
533
|
+
probeWith: 'スキルあり',
|
|
534
|
+
probeWithout: 'スキルなし',
|
|
535
|
+
probeAction: '最初の動作',
|
|
536
|
+
probeFiles: '変更されたファイル',
|
|
537
|
+
probeSame: '同じ',
|
|
538
|
+
probeDiffer: '異なる',
|
|
539
|
+
probeActionKind: '最初の動作の種類',
|
|
540
|
+
probeArtifacts: '生成されたファイル',
|
|
541
|
+
probeNoVerdict: '2 回の実行の事実を並べるだけで、「影響あり/なし」の自動判定は行いません。同じリクエストでも 2 回の実行でコマンド文字列が一致することはなく、「動作が異なる」はほぼ常に成り立つため、それで結論を出すのはコイン投げと変わりません。',
|
|
542
|
+
probeNoTrigger: 'このホストには発動率の数値がありません。構造上の理由です:Codex はスキルの呼び出しをイベントとして公開しません。',
|
|
543
|
+
codexEstimate: 'Codex はログイン済みの利用枠のみ使用します:{skills} 件のスキル × {runs} 回実行。現金コストは Codex のプランによります。',
|
|
544
|
+
codexStaticOnly: '静的チェックのみ実行:{skills} 件のスキル、モデル呼び出しは一切ありません。',
|
|
545
|
+
|
|
546
|
+
depthQ: 'どこまで深くテストしますか?',
|
|
547
|
+
depthQuick: 'クイック',
|
|
548
|
+
depthQuickHint: '約 1 分 · 「インストールして動くか」だけを確認',
|
|
549
|
+
depthStandard: '標準',
|
|
550
|
+
depthStandardHint: '約 5 分 · 信頼区間つきの発動率',
|
|
551
|
+
depthDeep: '詳細',
|
|
552
|
+
depthDeepHint: '約 10 分 · 読み取り専用の探索とペア比較の効果測定を追加',
|
|
553
|
+
providerQ: 'どのバックエンドを使いますか?',
|
|
554
|
+
provClaude: 'Claude Code サブスクリプション',
|
|
555
|
+
provClaudeHint: '現金不要、週間の利用枠を消費',
|
|
556
|
+
provDeepseek: 'DeepSeek',
|
|
557
|
+
provDeepseekHint: '現金はごくわずか、サブスクの利用枠は消費しない',
|
|
558
|
+
provManual: 'モデル名を手入力',
|
|
559
|
+
modelQ: 'モデル',
|
|
560
|
+
modelCheap: '最安',
|
|
561
|
+
modelDaily: '普段使いに最も近い',
|
|
562
|
+
modelExpensive: '最も高価',
|
|
563
|
+
needBaseUrl: '先にバックエンドを設定してください:\n ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic\n ANTHROPIC_AUTH_TOKEN=<あなたの key>',
|
|
564
|
+
backendLine: 'バックエンド:{backend} モデル:{model}',
|
|
565
|
+
estimate: '実行予定:{skills} 件のスキル × {trials} 回の試行 ≈ 1 件あたり {minutes} 分、合計約 {totalMinutes} 分\n費用はバックエンドとプランによります:サブスクリプションは利用枠を消費し、DeepSeek は従量課金です(ここでは金額を見積もりません)',
|
|
566
|
+
confirmRun: '続行しますか?',
|
|
567
|
+
cancelled: 'キャンセルしました。無料の静的チェックは確認不要です:npx skillgauntlet static <ディレクトリ>',
|
|
568
|
+
staticDone: '静的チェック:{verdicts}',
|
|
569
|
+
drafting: 'テスト用の質問を作成中(モデル呼び出し 1 回)…',
|
|
570
|
+
drafted: '{c} 件の発動条項について {q} 問を作成しました(キャッシュ済み、次回は再利用)',
|
|
571
|
+
queriesReused: 'キャッシュ済みの {n} 問({file})を再利用、質問作成の呼び出しを 1 回節約',
|
|
572
|
+
negativesChecked: '否定例 {n} 件すべてに検証可能な借用語があります',
|
|
573
|
+
weakNegatives: '警告:{total} 件の否定例のうち {weak} 件は、検証可能な借用語句を示せていません。description から離れすぎており、誤発動率が過小評価されます',
|
|
574
|
+
trialFail: '発動チェックに失敗しました:{err}',
|
|
575
|
+
gainSkip: '効果測定をスキップ({reason})',
|
|
576
|
+
gainNote: '効果測定の結果はローカルでの比較であり、アップロードされません。',
|
|
577
|
+
reportAt: 'レポート:{path}',
|
|
578
|
+
runSaved: '今回の実行を保存しました:{path}(raw.jsonl は試行ごとの記録 · meta.json は実行条件 · summary.json は集計)',
|
|
579
|
+
runStopped: '試行が {n} 回連続で失敗またはタイムアウトしたため自動停止しました({reason})。多くは利用上限、トークンの失効、ネットワーク断が原因です。完了済みの記録は保持され、集計は書き出されません。',
|
|
580
|
+
runIncomplete: '{n} 回の試行がエラーまたはタイムアウトとなり、補われていません。集計は残りの試行のみが対象です。',
|
|
581
|
+
resumeWith: '再開(完了済みはスキップし、エラーとタイムアウトは再試行):{cmd}',
|
|
582
|
+
resumeNothing: 'この実行には残りの試行がないため、再開する必要はありません。',
|
|
583
|
+
resumeDone: '再開が完了しました。今回 {n} 回の試行を実行しました。',
|
|
584
|
+
resumeMismatch: '再開できません:{what} は元は {was} でしたが、今回は {got} です。条件の異なる記録は統合できません。元の値に戻すか、新しい実行を始めてください。',
|
|
585
|
+
resumeQueriesChanged: '再開できません:質問セットがこの実行で使ったものと一致しません(ファイルが編集されたか、見つかりません)。',
|
|
586
|
+
resumeSkillChanged: '再開できません:この実行の開始後に SKILL.md が変更されています。',
|
|
587
|
+
shareState: '公開リーダーボードはまだないため、アップロードの確認は行わず、何もアップロードしません。上のディレクトリが将来の提出形式です。ボードが公開されたら、再実行せずにそのまま提出できます。',
|
|
588
|
+
inputEnded: '入力が終了しました',
|
|
589
|
+
err: 'エラー:{msg}',
|
|
590
|
+
modelRemap: 'バックエンド {host} は Anthropic のモデル名を黙って書き換えるため、「{model}」では指定したモデルをテストできません。そのバックエンド自身のモデル名を指定してください',
|
|
591
|
+
hostMissing: 'ホスト {host} が見つかりません(PATH に {bin} がありません)。{how}。または、もう一度実行して別のホスト(Claude Code、CodeBuddy、Codewhale、Codex)を選んでください。',
|
|
592
|
+
installCodebuddy: 'インストール方法:npm install -g @tencent-ai/codebuddy-code',
|
|
593
|
+
installCodewhale: 'インストール方法:公式リリースページから単体 exe をダウンロードし、codewhale.exe に改名して PATH に置いてください',
|
|
594
|
+
installClaude: 'インストール方法:npm install -g @anthropic-ai/claude-code',
|
|
595
|
+
badSource: 'このアドレスを解釈できません:{spec}(ローカルディレクトリか owner/repo を指定してください)',
|
|
596
|
+
noSkillUnder: '{target} の下に SKILL.md が見つかりません',
|
|
597
|
+
resumeUsage: '使い方:skillgauntlet resume <実行ディレクトリ> [--model M] [--runs N] [--max-explore N]',
|
|
598
|
+
'ui.yesWords': 'y,yes,はい,ハイ',
|
|
599
|
+
'ui.noWords': 'n,no,いいえ,イイエ',
|
|
600
|
+
usage: `SkillGauntlet
|
|
601
|
+
|
|
602
|
+
npx skillgauntlet 対話モード
|
|
603
|
+
npx skillgauntlet static <ディレクトリ> 層 0 のみ実行(モデル呼び出しなし)
|
|
604
|
+
npx skillgauntlet static <ディレクトリ> --json
|
|
605
|
+
npx skillgauntlet resume <実行ディレクトリ> 中断または自動停止した実行を再開(エラーとタイムアウトは再試行)
|
|
606
|
+
--lang zh|ja|en または環境変数 SG_LANG で言語を指定できます
|
|
607
|
+
|
|
608
|
+
層
|
|
609
|
+
0 静的 コンテキストコスト、権限範囲、コードのリスク、指示の乗っ取り、description の品質 無料
|
|
610
|
+
1 発動 発動すべきときに発動し、不要なときは静かにしているか モデル呼び出しあり
|
|
611
|
+
2 効果 スキルあり・なしの比較(プログラムで判定できるタスクのみ) モデル呼び出しあり
|
|
612
|
+
|
|
613
|
+
層 0 は必ず最初に実行されます。無料で、費用をかける前に大半の問題を弾けるためです。`,
|
|
614
|
+
|
|
615
|
+
'report.path': 'パス:',
|
|
616
|
+
'report.skillMd': 'SKILL.md:{chars} 文字 ≈ {tokens} トークン;description {desc} 文字',
|
|
617
|
+
'report.package': 'パッケージ:{files} ファイル(うち実行可能 {code})、合計 {size}',
|
|
618
|
+
'report.permissions': '宣言された権限範囲:{tools}',
|
|
619
|
+
'report.notDeclared': '宣言なし',
|
|
620
|
+
'report.groupHeader': 'グループ',
|
|
621
|
+
'report.verdictHeader': '判定',
|
|
622
|
+
'report.checkHeader': 'チェック項目',
|
|
623
|
+
'report.allPass': 'すべて合格',
|
|
624
|
+
'report.noComposite': '> このページは事実とフラグのみを報告し、加重合計スコアは出しません。加重スコアは監査も異議申し立てもできないためです。',
|
|
625
|
+
'report.legend': '✓ 合格 ! 警告 ✗ 不合格 · 情報のみ(欠陥ではなく仕様の可能性あり)',
|
|
626
|
+
'report.colon': ':',
|
|
627
|
+
|
|
628
|
+
'group.A': 'コンテキストコスト',
|
|
629
|
+
'group.B': '権限範囲',
|
|
630
|
+
'group.C': 'コードのリスク',
|
|
631
|
+
'group.D': '指示の乗っ取り',
|
|
632
|
+
'group.E': 'description の品質',
|
|
633
|
+
|
|
634
|
+
'check.A1.title': 'SKILL.md のサイズ',
|
|
635
|
+
'check.A1.detail': '{chars} 文字 ≈ {tokens} トークン',
|
|
636
|
+
'check.A1.heavy': '{chars} 文字 ≈ {tokens} トークン(発動のたびに本文全体がコンテキストに入る)',
|
|
637
|
+
'check.A2.title': 'description の長さ',
|
|
638
|
+
'check.A2.detail': '{chars} 文字(ホストはリクエストのたびにこの部分だけを読む。長さが誤発動の範囲を左右する)',
|
|
639
|
+
'check.A2.missing': 'description がないため、ホストは照合できない',
|
|
640
|
+
'check.A3.title': '段階的開示',
|
|
641
|
+
'check.A3.detail': '本文が外部ファイルを {n} 件参照しており、必要なときだけ読み込める',
|
|
642
|
+
'check.A3.none': '本文が外部ファイルを参照しておらず、内容がすべて一度にコンテキストへ入る',
|
|
643
|
+
'check.A4.title': 'パッケージのサイズ',
|
|
644
|
+
'check.A4.detail': '{size} / {files} ファイル',
|
|
645
|
+
'check.B1.title': 'allowed-tools の宣言',
|
|
646
|
+
'check.B1.declared': '宣言内容:{tools}',
|
|
647
|
+
'check.B1.missing': '権限範囲が宣言されておらず、ホストの既定値が適用される',
|
|
648
|
+
'check.B2.title': '宣言された範囲の広さ',
|
|
649
|
+
'check.B2.wide': '無制限の書き込み/実行権限を宣言している',
|
|
650
|
+
'check.B2.narrow': '宣言された範囲は限定的',
|
|
651
|
+
'check.B3.title': 'モデルによる自動呼び出し',
|
|
652
|
+
'check.B3.manual': 'disable-model-invocation が設定されており、手動でのみ呼び出せる(自動では発動しない)',
|
|
653
|
+
'check.B3.auto': 'モデルが自動で呼び出せる',
|
|
654
|
+
'check.B4.title': '同梱コード',
|
|
655
|
+
'check.B4.detail': '実行可能ファイル {n} 件:{list}',
|
|
656
|
+
'check.B4.none': 'ドキュメントのみで、実行可能ファイルなし',
|
|
657
|
+
'check.C1.title': 'ネットワーク呼び出し',
|
|
658
|
+
'check.C2.title': 'コマンド実行 / 動的評価',
|
|
659
|
+
'check.C3.title': '認証情報・環境変数へのアクセス',
|
|
660
|
+
'check.C4.title': '難読化の兆候',
|
|
661
|
+
'check.C5.title': 'インストールフック',
|
|
662
|
+
'check.C.none': '見つからず',
|
|
663
|
+
'check.C.hits': '{n} 件以上',
|
|
664
|
+
'check.C.escalated': '{n} 件以上、かつ権限範囲が未宣言',
|
|
665
|
+
'check.D1.title': '指示の上書き',
|
|
666
|
+
'check.D1.hit': '本文に「以前の指示を無視せよ」型のパターンがある',
|
|
667
|
+
'check.D2.title': '機密パスの要求',
|
|
668
|
+
'check.D2.hit': '本文が認証情報や環境変数へのアクセスを求めている',
|
|
669
|
+
'check.D3.title': 'データの外部送信の要求',
|
|
670
|
+
'check.D3.hit': '「URL へ送信/アップロード」型の表現あり。手動で確認してください',
|
|
671
|
+
'check.D4.title': '不可視文字',
|
|
672
|
+
'check.D4.hit': 'ゼロ幅文字または双方向制御文字を含み、ソース上では見えない',
|
|
673
|
+
'check.D5.title': '外部画像',
|
|
674
|
+
'check.D5.hit': '外部画像を参照している。読み込むだけで第三者へリクエストが飛ぶ',
|
|
675
|
+
'check.D.none': '見つからず',
|
|
676
|
+
'check.E1.title': 'description の有無',
|
|
677
|
+
'check.E1.detail': '{chars} 文字',
|
|
678
|
+
'check.E1.missing': 'なし',
|
|
679
|
+
'check.E2.title': '使うべき場面の記述',
|
|
680
|
+
'check.E2.hit': '発動条件の表現あり',
|
|
681
|
+
'check.E2.miss': '「いつ使うか」の記述がなく、モデルは意味から推測するしかない',
|
|
682
|
+
'check.E3.title': '範囲が広すぎないか',
|
|
683
|
+
'check.E3.hit': '「何でも」「すべて」「any」型の全称表現があり、誤発動の範囲が広い',
|
|
684
|
+
'check.E3.none': '全称表現は見つからず',
|
|
685
|
+
'check.E4.title': '発動条項の数(概算)',
|
|
686
|
+
'check.E4.detail': '約 {n} 件(区切り文字からの概算。質問作成時にモデルが判定した条項リストが正)',
|
|
687
|
+
'check.E5.title': '名前とディレクトリの一致',
|
|
688
|
+
'check.E5.detail': 'frontmatter の name = {name}、ディレクトリ = {dir}',
|
|
689
|
+
'check.E5.noname': 'name フィールドなし',
|
|
690
|
+
|
|
691
|
+
'poll.title': '主に使っているホストはどれですか?',
|
|
692
|
+
'poll.body': '1) Claude Code 2) Codex 3) その他 —— 数字 1 つで答えてください。',
|
|
693
|
+
'poll.why': '質問の理由:発動率は、スキルの明示的な呼び出しを公開しているホストでしか測れません。Codex のイベントストリームには skill 項目がないため、その列は「未測定」ではなく空欄です。読者がどのホストを使っているかで、このレポートが誰の役に立つか、次にどの層を作るべきかが決まります。回答はシグナルとしてのみ読み、割合としては扱いません。回答する人は自己選択であり、そこから比率は計算できないためです。',
|
|
694
|
+
'trial.title': '発動率',
|
|
695
|
+
'trial.modelLine': 'モデル:{model}({backend});ホスト:{host};1 問あたり {runs} 回、計 {trials} 回の試行',
|
|
696
|
+
'trial.hostUnknown': '記録なし',
|
|
697
|
+
'trial.recall': '再現率(発動すべき質問で実際に発動した割合):{p}(95% 信頼区間 {lo}–{hi})',
|
|
698
|
+
'trial.fpr': '誤発動率(発動すべきでない質問で発動した割合):{p}(95% 信頼区間 {lo}–{hi})',
|
|
699
|
+
'trial.noTool': '発動すべき質問のうち「ツールを一切呼ばずに回答した」割合:{p}',
|
|
700
|
+
'trial.noToolWarn': ' ← 多くの場合、description ではなくモデルやホスト側の問題',
|
|
701
|
+
'trial.stateHeader': '期待',
|
|
702
|
+
'trial.queryHeader': '質問',
|
|
703
|
+
'trial.hitsHeader': '発動回数',
|
|
704
|
+
'trial.should': '発動すべき',
|
|
705
|
+
'trial.shouldNot': '発動すべきでない',
|
|
706
|
+
|
|
707
|
+
'gain.title': '効果:スキルありとなしの比較(ローカル結果、アップロードされません)',
|
|
708
|
+
'gain.intro': '同じタスクをスキルありとなしで 2 回ずつ実行し、プログラムで判定できるコントラクト(検証条件)のうち、どれが満たされたかを見ます。',
|
|
709
|
+
'gain.local': 'これはあなた自身のための比較でありスコアではありません。内容はアップロードされず、リーダーボードにも載りません。',
|
|
710
|
+
'gain.contractHeader': 'コントラクト',
|
|
711
|
+
'gain.withHeader': 'あり',
|
|
712
|
+
'gain.withoutHeader': 'なし',
|
|
713
|
+
'gain.dirHeader': '方向',
|
|
714
|
+
'gain.up': '↑ 向上',
|
|
715
|
+
'gain.down': '↓ 低下',
|
|
716
|
+
'gain.same': '= 差なし',
|
|
717
|
+
'gain.perTask': 'タスクごとの、スキルあり・なしの違い',
|
|
718
|
+
'gain.withSkill': 'スキルあり',
|
|
719
|
+
'gain.withoutSkill': 'スキルなし',
|
|
720
|
+
'gain.noFiles': '新規ファイルなし',
|
|
721
|
+
'gain.side': '追加 {files} コントラクト {ok}/{n}',
|
|
722
|
+
'gain.footnote1': '> ここに載るのは、コントラクトファイルに明記され、プログラムで判定できる効果だけです。審美的なタスクや',
|
|
723
|
+
'gain.footnote2': '> 自由度の高いタスクは対象外です。LLM を審判にすれば扱えますが、そのスコアは再現も異議申し立てもできません。',
|
|
724
|
+
'gain.noContracts': 'このスキルにはコントラクトファイルがないため、アサーションによる効果の判定はできません',
|
|
725
|
+
},
|
|
726
|
+
};
|
|
727
|
+
|
|
728
|
+
let current = 'en';
|
|
729
|
+
|
|
730
|
+
export const LANGS = Object.keys(MESSAGES);
|
|
731
|
+
|
|
732
|
+
export function setLang(lang) {
|
|
733
|
+
current = MESSAGES[lang] ? lang : 'en';
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
export function lang() {
|
|
737
|
+
return current;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// SG_LANG wins; otherwise the OS locale; otherwise English.
|
|
741
|
+
export function detectLang(env = process.env) {
|
|
742
|
+
const want = String(env.SG_LANG || '').toLowerCase().slice(0, 2);
|
|
743
|
+
if (MESSAGES[want]) return want;
|
|
744
|
+
const loc = Intl.DateTimeFormat().resolvedOptions().locale.toLowerCase().slice(0, 2);
|
|
745
|
+
return MESSAGES[loc] ? loc : 'en';
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
export function t(key, vars = {}) {
|
|
749
|
+
const table = MESSAGES[current] || MESSAGES.en;
|
|
750
|
+
const raw = table[key] ?? MESSAGES.en[key] ?? key;
|
|
751
|
+
return raw.replace(/\{(\w+)\}/g, (_, k) => (vars[k] ?? `{${k}}`));
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// An error either carries a message key (translated) or is plain text from the runtime.
|
|
755
|
+
export function errorText(err) {
|
|
756
|
+
if (!err.messageKey) return err.message;
|
|
757
|
+
return t(err.messageKey, err.howKey ? { ...err.vars, how: t(err.howKey) } : err.vars);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// Comma-separated word list from the table, e.g. the accepted yes answers.
|
|
761
|
+
export function words(key) {
|
|
762
|
+
return t(key).split(',').map((w) => w.trim().toLowerCase()).filter(Boolean);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
export function messageTables() {
|
|
766
|
+
return MESSAGES;
|
|
767
|
+
}
|