opencode-agent-skill 10.0.0 → 12.0.0-beta.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/CHANGELOG.md +85 -0
- package/README.md +60 -8
- package/bin/ocskill.mjs +354 -6
- package/docs/DETERMINISTIC-TOOLS.md +1 -1
- package/docs/ENGINEERING-DESIGN.md +4 -4
- package/docs/EVALS.md +3 -3
- package/docs/GITHUB-RULESET.md +50 -0
- package/docs/NPM-PUBLISH.md +4 -4
- package/docs/OPENCODE-COMPAT.md +3 -3
- package/docs/TRACE-SCHEMA.md +1 -1
- package/docs/V11-PERCEPTION-ADAPTIVE-EXECUTION.md +75 -0
- package/docs/V11-PERCEPTION-ADAPTIVE.md +220 -0
- package/docs/V12-WEAK-MODEL-INTELLIGENCE.md +27 -0
- package/evals/repo-scale/tasks.json +62 -0
- package/evals/router-triggers.json +82 -0
- package/evals/routing.json +76 -0
- package/evals/v11/tasks.json +122 -0
- package/global-config/agents/merge-arbiter.md +12 -0
- package/global-config/agents/visual-verifier.md +12 -0
- package/global-config/plugins/ues-router/index.js +272 -2
- package/global-config/plugins/ues-router/router.js +27 -3
- package/global-config/skills/browser-qa/SKILL.md +14 -0
- package/global-config/skills/browser-qa/references/workflow.md +11 -0
- package/global-config/skills/browser-security/SKILL.md +12 -0
- package/global-config/skills/component-visual-testing/SKILL.md +10 -0
- package/global-config/skills/design-source/SKILL.md +10 -0
- package/global-config/skills/design-source/references/workflow.md +12 -0
- package/global-config/skills/dynamic-workflow/SKILL.md +18 -0
- package/global-config/skills/dynamic-workflow/references/workflow.md +19 -0
- package/global-config/skills/responsive-verification/SKILL.md +10 -0
- package/global-config/skills/skill-authoring/SKILL.md +12 -0
- package/global-config/skills/skill-evaluation/SKILL.md +17 -0
- package/global-config/skills/visual-fidelity/SKILL.md +14 -0
- package/global-config/skills/visual-fidelity/references/workflow.md +14 -0
- package/lib/browser-adapter.mjs +82 -0
- package/lib/browser-runtime.mjs +193 -0
- package/lib/capability-registry.mjs +109 -0
- package/lib/context-engine-v11.mjs +150 -0
- package/lib/context-manifest.mjs +16 -3
- package/lib/context-quality.mjs +59 -0
- package/lib/control-center.mjs +12 -2
- package/lib/decision-policy.mjs +23 -0
- package/lib/dynamic-workflow.mjs +179 -0
- package/lib/eval-ablation.mjs +43 -1
- package/lib/eval-report.mjs +72 -0
- package/lib/eval-telemetry.mjs +61 -0
- package/lib/evidence-budget.mjs +84 -0
- package/lib/evidence-store.mjs +178 -0
- package/lib/hermes-bridge.mjs +45 -1
- package/lib/model-config.mjs +21 -1
- package/lib/model-performance.mjs +113 -0
- package/lib/model-policy.mjs +59 -1
- package/lib/orchestrator-policy.mjs +1 -1
- package/lib/png-diff.mjs +229 -0
- package/lib/prompt-cache.mjs +60 -0
- package/lib/repo-scale-fixture.mjs +45 -0
- package/lib/skill-quality.mjs +72 -0
- package/lib/task-engine.mjs +95 -7
- package/lib/ui-inspector.mjs +152 -0
- package/lib/v11-metrics.mjs +64 -0
- package/lib/visual-spec.mjs +159 -0
- package/lib/work-plan-scope.mjs +49 -0
- package/package.json +13 -5
- package/scripts/check-release-consistency.mjs +228 -0
- package/scripts/eval-ablation.mjs +4 -1
- package/scripts/validate-repo-scale-suite.mjs +27 -0
- package/scripts/validate-v11-suite.mjs +58 -0
- package/scripts/validate-v12-foundation.mjs +24 -0
- package/scripts/validate.mjs +16 -4
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs"
|
|
4
|
+
import path from "node:path"
|
|
5
|
+
import { fileURLToPath } from "node:url"
|
|
6
|
+
|
|
7
|
+
const DEFAULT_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
|
|
8
|
+
|
|
9
|
+
function readJson(root, relative) {
|
|
10
|
+
const file = path.join(root, relative)
|
|
11
|
+
if (!existsSync(file)) {
|
|
12
|
+
return { ok: false, error: `${relative}: file not found`, value: null }
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
return { ok: true, error: null, value: JSON.parse(readFileSync(file, "utf8")) }
|
|
16
|
+
} catch (e) {
|
|
17
|
+
return { ok: false, error: `${relative}: invalid JSON (${e.message})`, value: null }
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function readText(root, relative) {
|
|
22
|
+
const file = path.join(root, relative)
|
|
23
|
+
if (!existsSync(file)) {
|
|
24
|
+
return { ok: false, error: `${relative}: file not found`, value: null }
|
|
25
|
+
}
|
|
26
|
+
return { ok: true, error: null, value: readFileSync(file, "utf8") }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function countSkillDirs(root) {
|
|
30
|
+
const fullPath = path.join(root, "global-config", "skills")
|
|
31
|
+
if (!existsSync(fullPath)) return { ok: false, error: "global-config/skills: directory not found", value: 0 }
|
|
32
|
+
const entries = readdirSync(fullPath, { withFileTypes: true })
|
|
33
|
+
const count = entries.filter((entry) => entry.isDirectory() && existsSync(path.join(fullPath, entry.name, "SKILL.md"))).length
|
|
34
|
+
return { ok: true, error: null, value: count }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function countDir(root, dirPath, filter) {
|
|
38
|
+
const fullPath = path.join(root, dirPath)
|
|
39
|
+
if (!existsSync(fullPath)) {
|
|
40
|
+
return { ok: false, error: `${dirPath}: directory not found`, value: 0 }
|
|
41
|
+
}
|
|
42
|
+
const entries = readdirSync(fullPath, { withFileTypes: true })
|
|
43
|
+
const count = filter ? entries.filter(filter).length : entries.length
|
|
44
|
+
return { ok: true, error: null, value: count }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function checkReleaseConsistency(root) {
|
|
48
|
+
root = root || DEFAULT_ROOT
|
|
49
|
+
const errors = []
|
|
50
|
+
const warnings = []
|
|
51
|
+
|
|
52
|
+
function rJson(relative) {
|
|
53
|
+
return readJson(root, relative)
|
|
54
|
+
}
|
|
55
|
+
function rText(relative) {
|
|
56
|
+
return readText(root, relative)
|
|
57
|
+
}
|
|
58
|
+
function rCount(dirPath, filter) {
|
|
59
|
+
return countDir(root, dirPath, filter)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 1. package.json version == package-lock.json version
|
|
63
|
+
const pkg = rJson("package.json")
|
|
64
|
+
const lock = rJson("package-lock.json")
|
|
65
|
+
if (pkg.ok && lock.ok) {
|
|
66
|
+
const pkgVersion = pkg.value.version
|
|
67
|
+
const lockVersion = lock.value.version
|
|
68
|
+
if (pkgVersion !== lockVersion) {
|
|
69
|
+
errors.push(`package.json version (${pkgVersion}) != package-lock.json version (${lockVersion})`)
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
if (!pkg.ok) errors.push(pkg.error)
|
|
73
|
+
if (!lock.ok) errors.push(lock.error)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 2. Count skills, commands, subagents
|
|
77
|
+
const skillRes = countSkillDirs(root)
|
|
78
|
+
const commandRes = rCount("global-config/commands", (e) => e.isFile() && e.name.endsWith(".md"))
|
|
79
|
+
const agentRes = rCount("global-config/agents", (e) => e.isFile() && e.name.endsWith(".md"))
|
|
80
|
+
const skillCount = skillRes.ok ? skillRes.value : 0
|
|
81
|
+
const commandCount = commandRes.ok ? commandRes.value : 0
|
|
82
|
+
const agentCount = agentRes.ok ? agentRes.value : 0
|
|
83
|
+
if (!skillRes.ok) errors.push(skillRes.error)
|
|
84
|
+
if (!commandRes.ok) errors.push(commandRes.error)
|
|
85
|
+
if (!agentRes.ok) errors.push(agentRes.error)
|
|
86
|
+
|
|
87
|
+
const expectedVersion = pkg.ok ? pkg.value.version : "unknown"
|
|
88
|
+
const routing = rJson("evals/routing.json")
|
|
89
|
+
const routerTriggers = rJson("evals/router-triggers.json")
|
|
90
|
+
const staticScenarioCount = routing.ok && Array.isArray(routing.value.scenarios) ? routing.value.scenarios.length : 0
|
|
91
|
+
const routerCaseCount = routerTriggers.ok && Array.isArray(routerTriggers.value.cases) ? routerTriggers.value.cases.length : 0
|
|
92
|
+
if (!routing.ok) errors.push(routing.error)
|
|
93
|
+
if (!routerTriggers.ok) errors.push(routerTriggers.error)
|
|
94
|
+
|
|
95
|
+
// 3. Check README current version block
|
|
96
|
+
const readme = rText("README.md")
|
|
97
|
+
if (readme.ok) {
|
|
98
|
+
const versionMatch = readme.value.match(/Phiên bản hiện tại:\s*\n```text\n(\S+)/)
|
|
99
|
+
if (versionMatch && versionMatch[1] !== expectedVersion) {
|
|
100
|
+
errors.push(`README.md: current version says ${versionMatch[1]}, expected ${expectedVersion}`)
|
|
101
|
+
} else if (!versionMatch) {
|
|
102
|
+
errors.push("README.md: could not find current version block")
|
|
103
|
+
}
|
|
104
|
+
if (staticScenarioCount && !readme.value.includes("**" + staticScenarioCount + " static skill-routing scenarios**")) {
|
|
105
|
+
errors.push("README.md: static routing scenario count drift (actual: " + staticScenarioCount + ")")
|
|
106
|
+
}
|
|
107
|
+
if (routerCaseCount && !readme.value.includes("**" + routerCaseCount + " V2 router cases**")) {
|
|
108
|
+
errors.push("README.md: router case count drift (actual: " + routerCaseCount + ")")
|
|
109
|
+
}
|
|
110
|
+
} else {
|
|
111
|
+
errors.push(readme.error)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 4. Check V11 docs for stale status markers
|
|
115
|
+
const v11Docs = ["docs/V11-PERCEPTION-ADAPTIVE.md", "docs/V11-PERCEPTION-ADAPTIVE-EXECUTION.md"]
|
|
116
|
+
for (const doc of v11Docs) {
|
|
117
|
+
const content = rText(doc)
|
|
118
|
+
if (!content.ok) {
|
|
119
|
+
errors.push(content.error)
|
|
120
|
+
continue
|
|
121
|
+
}
|
|
122
|
+
if (content.value.includes("Status: development")) {
|
|
123
|
+
errors.push(`${doc}: still marked as development`)
|
|
124
|
+
}
|
|
125
|
+
if (content.value.includes("11.0.0-dev.")) {
|
|
126
|
+
errors.push(`${doc}: still references dev version 11.0.0-dev.*`)
|
|
127
|
+
}
|
|
128
|
+
if (content.value.includes("npm `latest` remains V10")) {
|
|
129
|
+
errors.push(`${doc}: still says V10 remains npm latest`)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// 5. Verify docs reflect actual counts (skip historical sections)
|
|
134
|
+
const docsToCheck = ["README.md", "docs/ENGINEERING-DESIGN.md", "docs/OPENCODE-COMPAT.md"]
|
|
135
|
+
for (const doc of docsToCheck) {
|
|
136
|
+
const content = rText(doc)
|
|
137
|
+
if (!content.ok) {
|
|
138
|
+
errors.push(content.error)
|
|
139
|
+
continue
|
|
140
|
+
}
|
|
141
|
+
const sections = content.value.split(/\n(?=#{1,6}\s)/)
|
|
142
|
+
for (const section of sections) {
|
|
143
|
+
const isHistorical = /^\s*#{1,6}\s+.*(V\d+\.|UES\s+\d+\.|historical|Historical)/im.test(section)
|
|
144
|
+
if (isHistorical) continue
|
|
145
|
+
if (section.includes("39 skills") || section.includes("39 namespaced skills")) {
|
|
146
|
+
errors.push(`${doc}: current section still references 39 skills (actual: ${skillCount})`)
|
|
147
|
+
}
|
|
148
|
+
if (section.includes("10 namespaced subagents") || section.includes("10 subagents")) {
|
|
149
|
+
errors.push(`${doc}: current section still references 10 subagents (actual: ${agentCount})`)
|
|
150
|
+
}
|
|
151
|
+
if (section.includes("34 static") && section.includes("scenarios")) {
|
|
152
|
+
errors.push(`${doc}: current section still references 34 static scenarios (actual: ${staticScenarioCount})`)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// 6. Check CI workflow
|
|
158
|
+
const ciYaml = rText(".github/workflows/ci.yml")
|
|
159
|
+
if (ciYaml.ok) {
|
|
160
|
+
if (!ciYaml.value.includes("evals:v11:validate")) {
|
|
161
|
+
errors.push(".github/workflows/ci.yml: missing evals:v11:validate job")
|
|
162
|
+
}
|
|
163
|
+
if (!/^\s*name:\s*CI Gate\s*$/m.test(ciYaml.value)) errors.push(".github/workflows/ci.yml: missing CI Gate aggregate job name")
|
|
164
|
+
if (!/needs:\s*\[\s*static\s*,\s*unit\s*,\s*package\s*\]/m.test(ciYaml.value)) errors.push(".github/workflows/ci.yml: CI Gate must depend on static, unit and package")
|
|
165
|
+
if (!/if:\s*always\(\)/m.test(ciYaml.value)) errors.push(".github/workflows/ci.yml: aggregate gate must use if: always()")
|
|
166
|
+
if (!ciYaml.value.includes("docs:check")) errors.push(".github/workflows/ci.yml: missing docs:check job")
|
|
167
|
+
for (const check of ["evals:v12:validate","evals:repo-scale:validate"]) {
|
|
168
|
+
if (!ciYaml.value.includes(check)) errors.push(".github/workflows/ci.yml: missing " + check + " job")
|
|
169
|
+
}
|
|
170
|
+
} else {
|
|
171
|
+
errors.push(ciYaml.error)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// 7. Check Security workflow
|
|
175
|
+
const securityYaml = rText(".github/workflows/security.yml")
|
|
176
|
+
if (securityYaml.ok) {
|
|
177
|
+
if (!/^\s*name:\s*Security Gate\s*$/m.test(securityYaml.value)) errors.push(".github/workflows/security.yml: missing Security Gate aggregate job name")
|
|
178
|
+
if (!/needs:\s*\[\s*codeql\s*,\s*dependency-review\s*\]/m.test(securityYaml.value)) errors.push(".github/workflows/security.yml: Security Gate must depend on codeql and dependency-review")
|
|
179
|
+
} else {
|
|
180
|
+
errors.push(securityYaml.error)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// 8. Check publish workflow idempotency
|
|
184
|
+
const publishYaml = rText(".github/workflows/publish.yml")
|
|
185
|
+
if (publishYaml.ok) {
|
|
186
|
+
if (!publishYaml.value.includes("already published")) {
|
|
187
|
+
errors.push(".github/workflows/publish.yml: missing idempotency check for existing versions")
|
|
188
|
+
}
|
|
189
|
+
} else {
|
|
190
|
+
errors.push(publishYaml.error)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// 9. Check npm script docs:check exists
|
|
194
|
+
if (pkg.ok) {
|
|
195
|
+
const pkgScripts = pkg.value.scripts || {}
|
|
196
|
+
if (!pkgScripts["docs:check"]) {
|
|
197
|
+
warnings.push("package.json: missing docs:check npm script")
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
pass: errors.length === 0,
|
|
203
|
+
errors,
|
|
204
|
+
warnings,
|
|
205
|
+
version: expectedVersion,
|
|
206
|
+
skillCount,
|
|
207
|
+
commandCount,
|
|
208
|
+
subagentCount: agentCount,
|
|
209
|
+
staticScenarioCount,
|
|
210
|
+
routerCaseCount,
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
215
|
+
const result = checkReleaseConsistency(process.env.UES_BUNDLE_ROOT || DEFAULT_ROOT)
|
|
216
|
+
if (result.warnings.length) {
|
|
217
|
+
console.warn("Warnings:")
|
|
218
|
+
for (const w of result.warnings) console.warn(` WARN: ${w}`)
|
|
219
|
+
}
|
|
220
|
+
if (result.errors.length) {
|
|
221
|
+
console.error("Release consistency check FAILED:")
|
|
222
|
+
for (const e of result.errors) console.error(` - ${e}`)
|
|
223
|
+
process.exit(1)
|
|
224
|
+
}
|
|
225
|
+
console.log(
|
|
226
|
+
`Release consistency check PASS: package=${result.version}, skills=${result.skillCount}, commands=${result.commandCount}, subagents=${result.subagentCount}`,
|
|
227
|
+
)
|
|
228
|
+
}
|
|
@@ -14,7 +14,7 @@ function positional() {
|
|
|
14
14
|
const values = []
|
|
15
15
|
for (let index = 0; index < args.length; index += 1) {
|
|
16
16
|
if (args[index].startsWith("--")) {
|
|
17
|
-
if (["--pass-rate-tolerance", "--min-initial-reduction", "--max-token-ratio", "--max-duration-ratio"].includes(args[index])) index += 1
|
|
17
|
+
if (["--pass-rate-tolerance", "--min-initial-reduction", "--max-token-ratio", "--max-duration-ratio", "--min-cacheable-ratio", "--min-evidence-reuse-ratio", "--max-repeated-stable-ratio"].includes(args[index])) index += 1
|
|
18
18
|
continue
|
|
19
19
|
}
|
|
20
20
|
values.push(args[index])
|
|
@@ -38,6 +38,9 @@ const report = compareEvalSummaries(reference, candidate, {
|
|
|
38
38
|
minInitialInputReduction: Number(option("--min-initial-reduction", "0.10")),
|
|
39
39
|
maxTotalTokenRatio: Number(option("--max-token-ratio", "1.05")),
|
|
40
40
|
maxDurationRatio: Number(option("--max-duration-ratio", "1.10")),
|
|
41
|
+
minCacheableRatio: option("--min-cacheable-ratio", null) == null ? null : Number(option("--min-cacheable-ratio", null)),
|
|
42
|
+
minEvidenceReuseRatio: option("--min-evidence-reuse-ratio", null) == null ? null : Number(option("--min-evidence-reuse-ratio", null)),
|
|
43
|
+
maxRepeatedStableRatio: option("--max-repeated-stable-ratio", null) == null ? null : Number(option("--max-repeated-stable-ratio", null)),
|
|
41
44
|
})
|
|
42
45
|
|
|
43
46
|
console.log(JSON.stringify(report, null, 2))
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { mkdtemp, readFile, rm } from "node:fs/promises"
|
|
3
|
+
import os from "node:os"
|
|
4
|
+
import path from "node:path"
|
|
5
|
+
import { fileURLToPath } from "node:url"
|
|
6
|
+
import { generateRepoScaleFixture } from "../lib/repo-scale-fixture.mjs"
|
|
7
|
+
|
|
8
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
|
|
9
|
+
const suite = JSON.parse(await readFile(path.join(root, "evals", "repo-scale", "tasks.json"), "utf8"))
|
|
10
|
+
const errors = []
|
|
11
|
+
if (!Array.isArray(suite.tasks) || suite.tasks.length < 4) errors.push("repo-scale suite must define at least 4 tasks")
|
|
12
|
+
for (const task of suite.tasks || []) {
|
|
13
|
+
if (!task.id || !task.objective || task.objective.length < 40) errors.push((task.id || "<missing>") + ": objective too weak")
|
|
14
|
+
if (!Array.isArray(task.requiredFiles) || task.requiredFiles.length < 2) errors.push((task.id || "<missing>") + ": requiredFiles must contain at least 2 paths")
|
|
15
|
+
if (!Array.isArray(task.acceptance) || task.acceptance.length < 2) errors.push((task.id || "<missing>") + ": acceptance must contain at least 2 checks")
|
|
16
|
+
}
|
|
17
|
+
const tmp = await mkdtemp(path.join(os.tmpdir(), "ues-repo-scale-"))
|
|
18
|
+
try {
|
|
19
|
+
const generated = await generateRepoScaleFixture(tmp)
|
|
20
|
+
if (generated.generatedModules < Number(suite.minimumGeneratedModules || 300)) errors.push("generated repo too small: " + generated.generatedModules + " modules")
|
|
21
|
+
} finally { await rm(tmp, { recursive: true, force: true }) }
|
|
22
|
+
if (errors.length) {
|
|
23
|
+
console.error("Repo-scale suite validation failed:")
|
|
24
|
+
for (const error of errors) console.error("- " + error)
|
|
25
|
+
process.exit(1)
|
|
26
|
+
}
|
|
27
|
+
console.log("Validated repo-scale suite: " + suite.tasks.length + " tasks, >=" + suite.minimumGeneratedModules + " generated modules.")
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { existsSync } from "node:fs"
|
|
2
|
+
import { readFile } from "node:fs/promises"
|
|
3
|
+
import path from "node:path"
|
|
4
|
+
import { fileURLToPath } from "node:url"
|
|
5
|
+
|
|
6
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
|
|
7
|
+
const file = path.join(root, "evals", "v11", "tasks.json")
|
|
8
|
+
const suite = JSON.parse(await readFile(file, "utf8"))
|
|
9
|
+
const errors = []
|
|
10
|
+
|
|
11
|
+
const REQUIRED_V11_FILES = [
|
|
12
|
+
"lib/context-engine-v11.mjs",
|
|
13
|
+
"lib/evidence-store.mjs",
|
|
14
|
+
"lib/evidence-budget.mjs",
|
|
15
|
+
"lib/prompt-cache.mjs",
|
|
16
|
+
"lib/capability-registry.mjs",
|
|
17
|
+
"lib/browser-adapter.mjs",
|
|
18
|
+
"lib/browser-runtime.mjs",
|
|
19
|
+
"lib/png-diff.mjs",
|
|
20
|
+
"lib/visual-spec.mjs",
|
|
21
|
+
"lib/dynamic-workflow.mjs",
|
|
22
|
+
"lib/skill-quality.mjs",
|
|
23
|
+
"lib/ui-inspector.mjs",
|
|
24
|
+
"lib/v11-metrics.mjs",
|
|
25
|
+
"global-config/agents/visual-verifier.md",
|
|
26
|
+
"global-config/agents/merge-arbiter.md",
|
|
27
|
+
]
|
|
28
|
+
for (const relative of REQUIRED_V11_FILES) {
|
|
29
|
+
if (!existsSync(path.join(root, relative))) errors.push("missing V11 runtime file: " + relative)
|
|
30
|
+
}
|
|
31
|
+
const ids = new Set()
|
|
32
|
+
const categories = new Set()
|
|
33
|
+
|
|
34
|
+
if (!Array.isArray(suite.tasks) || suite.tasks.length < 10) errors.push("V11 suite must contain at least 10 tasks")
|
|
35
|
+
|
|
36
|
+
for (const task of suite.tasks || []) {
|
|
37
|
+
if (!task.id || ids.has(task.id)) errors.push("missing/duplicate id: " + (task.id || "<missing>"))
|
|
38
|
+
ids.add(task.id)
|
|
39
|
+
if (!task.category) errors.push((task.id || "<missing>") + ": missing category")
|
|
40
|
+
categories.add(task.category)
|
|
41
|
+
if (!task.objective || task.objective.length < 30) errors.push((task.id || "<missing>") + ": objective is too weak")
|
|
42
|
+
if (!Array.isArray(task.requiredFiles) || !task.requiredFiles.length) errors.push((task.id || "<missing>") + ": requiredFiles missing")
|
|
43
|
+
for (const relative of task.requiredFiles || []) {
|
|
44
|
+
if (!existsSync(path.join(root, relative))) errors.push((task.id || "<missing>") + ": missing required file " + relative)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
for (const category of ["context","routing","visual","browser","workflow","sidecar"]) {
|
|
49
|
+
if (!categories.has(category)) errors.push("V11 suite missing category: " + category)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (errors.length) {
|
|
53
|
+
console.error("V11 suite validation failed:")
|
|
54
|
+
for (const error of errors) console.error("- " + error)
|
|
55
|
+
process.exit(1)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
console.log("Validated " + suite.tasks.length + " V11 contract tasks across " + categories.size + " categories and " + REQUIRED_V11_FILES.length + " required runtime files.")
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync } from "node:fs"
|
|
3
|
+
import { readFile } from "node:fs/promises"
|
|
4
|
+
import path from "node:path"
|
|
5
|
+
import { fileURLToPath } from "node:url"
|
|
6
|
+
|
|
7
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
|
|
8
|
+
const errors = []
|
|
9
|
+
const required = [
|
|
10
|
+
"lib/model-performance.mjs","lib/context-quality.mjs","lib/work-plan-scope.mjs",
|
|
11
|
+
"lib/decision-policy.mjs","lib/repo-scale-fixture.mjs","evals/repo-scale/tasks.json",
|
|
12
|
+
"scripts/validate-repo-scale-suite.mjs",
|
|
13
|
+
]
|
|
14
|
+
for (const relative of required) if (!existsSync(path.join(root, relative))) errors.push("missing V12 foundation file: " + relative)
|
|
15
|
+
const pkg = JSON.parse(await readFile(path.join(root, "package.json"), "utf8"))
|
|
16
|
+
for (const script of ["evals:v12:validate","evals:repo-scale:validate"]) if (!pkg.scripts?.[script]) errors.push("package.json missing script " + script)
|
|
17
|
+
const tasks = JSON.parse(await readFile(path.join(root, "evals", "repo-scale", "tasks.json"), "utf8"))
|
|
18
|
+
if ((tasks.tasks || []).length < 4) errors.push("V12 repo-scale suite needs at least 4 contract tasks")
|
|
19
|
+
if (errors.length) {
|
|
20
|
+
console.error("V12 foundation validation failed:")
|
|
21
|
+
for (const error of errors) console.error("- " + error)
|
|
22
|
+
process.exit(1)
|
|
23
|
+
}
|
|
24
|
+
console.log("Validated V12 weak-model intelligence foundation files and repo-scale contracts.")
|
package/scripts/validate.mjs
CHANGED
|
@@ -87,9 +87,12 @@ for (const entry of await readdir(agentsRoot, { withFileTypes: true })) {
|
|
|
87
87
|
if (!/mode:\s*subagent/.test(source)) errors.push(`${entry.name}: agent must use mode: subagent`)
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
const V11_REQUIRED_SKILLS = ["visual-fidelity","browser-qa","design-source","responsive-verification","component-visual-testing","browser-security","skill-authoring","skill-evaluation","dynamic-workflow"]
|
|
91
|
+
for (const id of V11_REQUIRED_SKILLS) if (!ids.has(id)) errors.push(`missing V11 skill ${id}`)
|
|
92
|
+
|
|
93
|
+
if (ids.size < 48) errors.push(`expected at least 48 skills for V11, found ${ids.size}`)
|
|
91
94
|
if (commands < 11) errors.push(`expected at least 11 commands, found ${commands}`)
|
|
92
|
-
if (agents <
|
|
95
|
+
if (agents < 12) errors.push(`expected at least 12 subagents for V11, found ${agents}`)
|
|
93
96
|
|
|
94
97
|
const routerIndex = path.join(pluginsRoot, "ues-router", "index.js")
|
|
95
98
|
const routerCore = path.join(pluginsRoot, "ues-router", "router.js")
|
|
@@ -115,6 +118,15 @@ if (existsSync(routerIndex)) {
|
|
|
115
118
|
if (!source.includes('name: "task_policy"')) errors.push("v8 router plugin must expose adaptive task policy")
|
|
116
119
|
if (!source.includes('name: "cancel_task"')) errors.push("v8 router plugin must expose executor cancellation")
|
|
117
120
|
if (!source.includes('name: "recover_task"')) errors.push("v8 router plugin must expose task-scoped recovery")
|
|
121
|
+
if (!source.includes('name: "capability_requirements"')) errors.push("v11 router plugin must expose capability requirements")
|
|
122
|
+
if (!source.includes('name: "evidence_get"')) errors.push("v11 router plugin must expose bounded evidence retrieval")
|
|
123
|
+
if (!source.includes('name: "browser_plan"')) errors.push("v11 router plugin must expose browser verification planning")
|
|
124
|
+
if (!source.includes('name: "browser_inspect"')) errors.push("v11 router plugin must expose bounded browser inspection")
|
|
125
|
+
if (!source.includes('name: "visual_geometry"')) errors.push("v11 router plugin must expose visual geometry receipts")
|
|
126
|
+
if (!source.includes('name: "visual_compare"')) errors.push("v11 router plugin must expose deterministic PNG comparison")
|
|
127
|
+
if (!source.includes('name: "workflow_plan"')) errors.push("v11 router plugin must expose dynamic workflow planning")
|
|
128
|
+
if (!source.includes('name: "ui_tokens"')) errors.push("v11 router plugin must expose compact design-token extraction")
|
|
129
|
+
if (!source.includes('name: "ui_layout"')) errors.push("v11 router plugin must expose responsive UI layout verification")
|
|
118
130
|
if (!source.includes("ctx.session.interrupt")) errors.push("v8 task dispatch must interrupt timed-out executors")
|
|
119
131
|
if (!source.includes('"work", "heartbeat"')) errors.push("v8 task dispatch must refresh task leases")
|
|
120
132
|
}
|
|
@@ -138,11 +150,11 @@ if (existsSync(plainInstallSmoke)) {
|
|
|
138
150
|
}
|
|
139
151
|
}
|
|
140
152
|
|
|
141
|
-
for (const name of ["process-runner.mjs","evidence-receipt.mjs","gate-receipt.mjs","runtime-events.mjs","context-manifest.mjs","orchestrator-policy.mjs","worktree-sandbox.mjs","learning-engine.mjs","hermes-bridge.mjs","control-center.mjs"]) {
|
|
153
|
+
for (const name of ["process-runner.mjs","evidence-receipt.mjs","gate-receipt.mjs","runtime-events.mjs","context-manifest.mjs","orchestrator-policy.mjs","worktree-sandbox.mjs","learning-engine.mjs","hermes-bridge.mjs","control-center.mjs","evidence-store.mjs","evidence-budget.mjs","prompt-cache.mjs","capability-registry.mjs","visual-spec.mjs","png-diff.mjs","browser-adapter.mjs","browser-runtime.mjs","dynamic-workflow.mjs","skill-quality.mjs","ui-inspector.mjs","context-engine-v11.mjs","v11-metrics.mjs"]) {
|
|
142
154
|
if (!existsSync(path.join(root, "lib", name))) errors.push(`missing V8 core module ${name}`)
|
|
143
155
|
}
|
|
144
156
|
|
|
145
|
-
for (const name of ["codebase-mapper.md","plan-checker.md","executor.md","integration-verifier.md"]) {
|
|
157
|
+
for (const name of ["codebase-mapper.md","plan-checker.md","executor.md","integration-verifier.md","visual-verifier.md","merge-arbiter.md"]) {
|
|
146
158
|
if (!existsSync(path.join(agentsRoot, name))) errors.push(`missing V6 subagent ${name}`)
|
|
147
159
|
}
|
|
148
160
|
|