opencode-agent-skill 7.7.0 → 9.0.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 +63 -3
- package/README.md +675 -581
- package/bin/ocskill.mjs +358 -156
- package/docs/DETERMINISTIC-TOOLS.md +25 -8
- package/docs/ENGINEERING-DESIGN.md +31 -13
- package/docs/EVALS.md +34 -12
- package/docs/NPM-PUBLISH.md +6 -6
- package/docs/OPENCODE-COMPAT.md +11 -8
- package/docs/TRACE-SCHEMA.md +15 -2
- package/docs/V8-INTELLIGENCE-RELIABILITY.md +206 -0
- package/docs/V9-SPEED-INTELLIGENCE.md +102 -0
- package/evals/live/tasks.json +6 -6
- package/evals/polyglot/fixtures/polyglot-bench/api/generated/client.ts +2 -0
- package/evals/polyglot/fixtures/polyglot-bench/api/openapi.json +25 -0
- package/evals/polyglot/fixtures/polyglot-bench/db/migrations/20260920_add_order_key.sql +1 -0
- package/evals/polyglot/fixtures/polyglot-bench/dotnet/OrderService.cs +8 -0
- package/evals/polyglot/fixtures/polyglot-bench/java/PriceService.java +5 -0
- package/evals/polyglot/fixtures/polyglot-bench/monorepo/package.json +6 -0
- package/evals/polyglot/fixtures/polyglot-bench/monorepo/packages/api/package.json +4 -0
- package/evals/polyglot/fixtures/polyglot-bench/monorepo/packages/web/package.json +7 -0
- package/evals/polyglot/fixtures/polyglot-bench/monorepo/pnpm-lock.yaml +5 -0
- package/evals/polyglot/fixtures/polyglot-bench/next/app/api/products/route.ts +7 -0
- package/evals/polyglot/fixtures/polyglot-bench/python/tenant_auth.py +4 -0
- package/evals/polyglot/fixtures/polyglot-bench/react-native/keyboard.ts +3 -0
- package/evals/polyglot/graders/polyglot-bench.mjs +101 -0
- package/evals/polyglot/tasks.json +54 -0
- package/global-config/AGENTS.md +10 -7
- package/global-config/agents/integration-verifier.md +1 -1
- package/global-config/agents/plan-checker.md +1 -1
- package/global-config/commands/run.md +9 -5
- package/global-config/plugins/ues-router/capabilities.js +4 -0
- package/global-config/plugins/ues-router/index.js +414 -21
- package/global-config/plugins/ues-router/router.js +140 -23
- package/global-config/skills/engineering-orchestrator/references/long-horizon.md +6 -4
- package/lib/aci.mjs +128 -0
- package/lib/benchmark-confidence.mjs +135 -0
- package/lib/cli-utils.mjs +41 -0
- package/lib/container-sandbox.mjs +102 -0
- package/lib/context-manifest.mjs +300 -22
- package/lib/control-center.mjs +36 -3
- package/lib/eval-order.mjs +9 -0
- package/lib/eval-telemetry.mjs +5 -2
- package/lib/gate-receipt.mjs +52 -0
- package/lib/installer.mjs +39 -25
- package/lib/learning-engine.mjs +236 -38
- package/lib/opencode-compat.mjs +25 -10
- package/lib/orchestrator-policy.mjs +101 -20
- package/lib/process-runner.mjs +30 -9
- package/lib/runtime-events.mjs +31 -0
- package/lib/semantic-index.mjs +318 -0
- package/lib/task-engine.mjs +416 -24
- package/lib/trajectory.mjs +89 -0
- package/lib/windows-shim.mjs +227 -0
- package/lib/worktree-sandbox.mjs +85 -3
- package/package.json +10 -4
- package/scripts/check-release-tag.mjs +22 -0
- package/scripts/control-center.mjs +25 -0
- package/scripts/eval-live.mjs +39 -58
- package/scripts/eval-matrix.mjs +155 -0
- package/scripts/smoke-packed-install.mjs +138 -4
- package/scripts/smoke-plain-install.mjs +91 -0
- package/scripts/validate-live-suite.mjs +3 -3
- package/scripts/validate.mjs +27 -5
package/scripts/eval-live.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync
|
|
1
|
+
import { existsSync } from "node:fs"
|
|
2
2
|
import { cp, mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises"
|
|
3
3
|
import os from "node:os"
|
|
4
4
|
import path from "node:path"
|
|
@@ -7,9 +7,11 @@ import { fileURLToPath } from "node:url"
|
|
|
7
7
|
import { installResources } from "../lib/installer.mjs"
|
|
8
8
|
import { copyCurrentOpenCodeAuth } from "../lib/eval-auth.mjs"
|
|
9
9
|
import { parseOpenCodeTelemetry } from "../lib/eval-telemetry.mjs"
|
|
10
|
+
import { evalModeOrder } from "../lib/eval-order.mjs"
|
|
10
11
|
import { buildOpenCodeRunArgs, parseOpenCodeMajor } from "../lib/opencode-compat.mjs"
|
|
11
12
|
import { snapshotWorkspace, diffWorkspaceSnapshots } from "../lib/workspace-snapshot.mjs"
|
|
12
13
|
import { runProcess } from "../lib/process-runner.mjs"
|
|
14
|
+
import { resolveWindowsCommand } from "../lib/windows-shim.mjs"
|
|
13
15
|
|
|
14
16
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
|
|
15
17
|
const args = process.argv.slice(2)
|
|
@@ -35,69 +37,39 @@ function positiveInt(value, fallback) {
|
|
|
35
37
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback
|
|
36
38
|
}
|
|
37
39
|
|
|
38
|
-
function findWindowsCommand(name) {
|
|
39
|
-
if (path.isAbsolute(name) && existsSync(name)) return name
|
|
40
|
-
const result = spawnSync("where", [name], { encoding: "utf8" })
|
|
41
|
-
if (result.status !== 0 || !result.stdout) return null
|
|
42
|
-
const matches = result.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean)
|
|
43
|
-
return matches.find((item) => /\.(exe|cmd|bat)$/i.test(item)) || matches[0] || null
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function quoteCmd(value) {
|
|
47
|
-
if (/^[A-Za-z0-9_@%+=:,./\\-]+$/.test(value)) return value
|
|
48
|
-
return '"' + value.replaceAll('"', '""') + '"'
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function findNodeShimEntry(cmdPath) {
|
|
52
|
-
const dir = path.dirname(cmdPath)
|
|
53
|
-
let shim = ""
|
|
54
|
-
try {
|
|
55
|
-
shim = readFileSync(cmdPath, "utf8")
|
|
56
|
-
} catch {
|
|
57
|
-
return null
|
|
58
|
-
}
|
|
59
|
-
const match = shim.match(/node_modules[\\/][^\s"]+?\.(?:js|mjs)/gi)?.at(-1)
|
|
60
|
-
if (!match) return null
|
|
61
|
-
const entry = path.resolve(dir, match)
|
|
62
|
-
return existsSync(entry) ? entry : null
|
|
63
|
-
}
|
|
64
40
|
|
|
65
41
|
function runCommand(executable, commandArgs, options = {}) {
|
|
66
42
|
if (process.platform !== "win32") {
|
|
67
43
|
return spawnSync(executable, commandArgs, options)
|
|
68
44
|
}
|
|
69
45
|
|
|
70
|
-
const resolved =
|
|
46
|
+
const resolved = resolveWindowsCommand(executable)
|
|
71
47
|
if (!resolved) {
|
|
72
|
-
return {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if (entry) return spawnSync(process.execPath, [entry, ...commandArgs], options)
|
|
78
|
-
|
|
79
|
-
const line = [resolved, ...commandArgs].map(quoteCmd).join(" ")
|
|
80
|
-
return spawnSync(
|
|
81
|
-
process.env.ComSpec || "cmd.exe",
|
|
82
|
-
["/d", "/s", "/c", line],
|
|
83
|
-
options,
|
|
84
|
-
)
|
|
48
|
+
return {
|
|
49
|
+
status: 127,
|
|
50
|
+
stdout: "",
|
|
51
|
+
stderr: "No safely executable Windows command found for: " + executable,
|
|
52
|
+
}
|
|
85
53
|
}
|
|
86
54
|
|
|
87
|
-
return spawnSync(
|
|
55
|
+
return spawnSync(
|
|
56
|
+
resolved.executable,
|
|
57
|
+
[...resolved.argsPrefix, ...commandArgs],
|
|
58
|
+
options,
|
|
59
|
+
)
|
|
88
60
|
}
|
|
89
61
|
|
|
90
62
|
|
|
91
63
|
function runAsyncCommand(executable, commandArgs, options = {}) {
|
|
92
64
|
if (process.platform !== "win32") return runProcess(executable, commandArgs, options)
|
|
93
65
|
|
|
94
|
-
const resolved =
|
|
66
|
+
const resolved = resolveWindowsCommand(executable)
|
|
95
67
|
if (!resolved) {
|
|
96
68
|
return Promise.resolve({
|
|
97
69
|
status: 127,
|
|
98
70
|
signal: null,
|
|
99
71
|
stdout: "",
|
|
100
|
-
stderr: "
|
|
72
|
+
stderr: "No safely executable Windows command found for: " + executable,
|
|
101
73
|
durationMs: 0,
|
|
102
74
|
timedOut: false,
|
|
103
75
|
idleTimedOut: false,
|
|
@@ -105,14 +77,11 @@ function runAsyncCommand(executable, commandArgs, options = {}) {
|
|
|
105
77
|
})
|
|
106
78
|
}
|
|
107
79
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return runProcess(resolved, commandArgs, options)
|
|
80
|
+
return runProcess(
|
|
81
|
+
resolved.executable,
|
|
82
|
+
[...resolved.argsPrefix, ...commandArgs],
|
|
83
|
+
options,
|
|
84
|
+
)
|
|
116
85
|
}
|
|
117
86
|
|
|
118
87
|
function excerpt(value, limit = 12000) {
|
|
@@ -145,6 +114,10 @@ async function inspectLongOrchestration(workspace) {
|
|
|
145
114
|
slug: entry.name,
|
|
146
115
|
taskCount: Array.isArray(plan.tasks) ? plan.tasks.length : 0,
|
|
147
116
|
planApproved: state.planApproval?.status === "passed",
|
|
117
|
+
structuredPlanReceipt:
|
|
118
|
+
state.planApproval?.receipt?.kind === "plan-verification" &&
|
|
119
|
+
state.planApproval?.receipt?.verdict === "PASS" &&
|
|
120
|
+
state.planApproval?.receipt?.planHash === state.planHash,
|
|
148
121
|
attemptedTasks: tasks.filter((task) => Number(task.attempts || 0) > 0).length,
|
|
149
122
|
completedTasks: tasks.filter((task) => task.status === "completed").length,
|
|
150
123
|
receiptBackedTasks: plannedIDs.filter((id) => receiptBackedTasks.has(id)).length,
|
|
@@ -152,6 +125,10 @@ async function inspectLongOrchestration(workspace) {
|
|
|
152
125
|
? plannedIDs.filter((id) => receiptBackedTasks.has(id)).length / plannedIDs.length
|
|
153
126
|
: 0,
|
|
154
127
|
integrationPassed: state.integrationVerification?.status === "PASS",
|
|
128
|
+
structuredIntegrationReceipt:
|
|
129
|
+
state.integrationVerification?.receipt?.kind === "integration-verification" &&
|
|
130
|
+
state.integrationVerification?.receipt?.verdict === "PASS" &&
|
|
131
|
+
state.integrationVerification?.receipt?.workspaceFingerprint === state.integrationVerification?.fingerprint,
|
|
155
132
|
integrationEvidence: evidenceTasks.has("__integration_verification__"),
|
|
156
133
|
finalizedEvidence: evidenceTasks.has("__integration__"),
|
|
157
134
|
completed: state.status === "completed",
|
|
@@ -159,10 +136,12 @@ async function inspectLongOrchestration(workspace) {
|
|
|
159
136
|
item.valid =
|
|
160
137
|
item.taskCount >= 2 &&
|
|
161
138
|
item.planApproved &&
|
|
139
|
+
item.structuredPlanReceipt &&
|
|
162
140
|
item.attemptedTasks === item.taskCount &&
|
|
163
141
|
item.completedTasks === item.taskCount &&
|
|
164
142
|
item.receiptBackedTasks === item.taskCount &&
|
|
165
143
|
item.integrationPassed &&
|
|
144
|
+
item.structuredIntegrationReceipt &&
|
|
166
145
|
item.integrationEvidence &&
|
|
167
146
|
item.finalizedEvidence &&
|
|
168
147
|
item.completed
|
|
@@ -193,7 +172,7 @@ const heartbeatMs = positiveInt(argValue("--heartbeat-ms"), 30_000)
|
|
|
193
172
|
const suiteRoot = path.join(root, "evals", suiteName)
|
|
194
173
|
|
|
195
174
|
if (!model) {
|
|
196
|
-
console.error("Usage: node scripts/eval-live.mjs --model provider/model [--suite live|long] [--variant high] [--trials N] [--task id] [--mode baseline|ues|both] [--auth env-only|current] [--output-dir path] [--keep] [--timeout-ms N] [--idle-timeout-ms N] [--heartbeat-ms N]")
|
|
175
|
+
console.error("Usage: node scripts/eval-live.mjs --model provider/model [--suite live|long|polyglot] [--variant high] [--trials N] [--task id] [--mode baseline|ues|both] [--auth env-only|current] [--output-dir path] [--keep] [--timeout-ms N] [--idle-timeout-ms N] [--heartbeat-ms N]")
|
|
197
176
|
console.error("You can also set UES_EVAL_MODEL and UES_EVAL_VARIANT.")
|
|
198
177
|
process.exit(2)
|
|
199
178
|
}
|
|
@@ -221,8 +200,8 @@ if (parsedOpenCodeMajor === null) {
|
|
|
221
200
|
console.warn("[eval] could not parse OpenCode version; using the conservative OpenCode 1.x invocation.")
|
|
222
201
|
}
|
|
223
202
|
|
|
224
|
-
if (!["live", "long"].includes(suiteName)) {
|
|
225
|
-
console.error("--suite must be live or
|
|
203
|
+
if (!["live", "long", "polyglot"].includes(suiteName)) {
|
|
204
|
+
console.error("--suite must be live, long, or polyglot")
|
|
226
205
|
process.exit(2)
|
|
227
206
|
}
|
|
228
207
|
|
|
@@ -246,11 +225,12 @@ const results = []
|
|
|
246
225
|
const oldConfigDir = process.env.OPENCODE_CONFIG_DIR
|
|
247
226
|
|
|
248
227
|
try {
|
|
249
|
-
for (const task of tasks) {
|
|
228
|
+
for (const [taskIndex, task] of tasks.entries()) {
|
|
250
229
|
if (interrupted) break
|
|
251
|
-
for (
|
|
230
|
+
for (let trial = 1; trial <= trials; trial += 1) {
|
|
252
231
|
if (interrupted) break
|
|
253
|
-
|
|
232
|
+
const trialModes = evalModeOrder(requestedMode, taskIndex, trial)
|
|
233
|
+
for (const mode of trialModes) {
|
|
254
234
|
if (interrupted) break
|
|
255
235
|
const isolatedRoot = path.join(runRoot, task.id + "-" + mode + "-" + trial)
|
|
256
236
|
const workspace = path.join(isolatedRoot, "workspace")
|
|
@@ -419,6 +399,7 @@ await writeFile(
|
|
|
419
399
|
opencodeVersion,
|
|
420
400
|
opencodeMajor,
|
|
421
401
|
modes,
|
|
402
|
+
ordering: requestedMode === "both" ? "counterbalanced-task-trial" : "single-mode",
|
|
422
403
|
summary,
|
|
423
404
|
results,
|
|
424
405
|
},
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from "node:child_process"
|
|
3
|
+
import { mkdir, readdir, readFile, writeFile } from "node:fs/promises"
|
|
4
|
+
import path from "node:path"
|
|
5
|
+
import { fileURLToPath } from "node:url"
|
|
6
|
+
import { summarizeEvalResults } from "../lib/eval-report.mjs"
|
|
7
|
+
import { pairedBenchmarkConfidence } from "../lib/benchmark-confidence.mjs"
|
|
8
|
+
|
|
9
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
|
|
10
|
+
const args = process.argv.slice(2)
|
|
11
|
+
|
|
12
|
+
function argValue(name, fallback = null) {
|
|
13
|
+
const index = args.indexOf(name)
|
|
14
|
+
return index >= 0 && index + 1 < args.length ? args[index + 1] : fallback
|
|
15
|
+
}
|
|
16
|
+
function has(name) { return args.includes(name) }
|
|
17
|
+
function positiveInt(value, fallback) {
|
|
18
|
+
const parsed = Number.parseInt(value || "", 10)
|
|
19
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const model = argValue("--model", process.env.UES_EVAL_MODEL)
|
|
23
|
+
const variant = argValue("--variant", process.env.UES_EVAL_VARIANT)
|
|
24
|
+
const trials = Math.min(positiveInt(argValue("--trials"), 3), 10)
|
|
25
|
+
const auth = argValue("--auth", "current")
|
|
26
|
+
const outputDir = path.resolve(argValue("--output-dir", path.join(process.cwd(), ".ues-evals", "matrix")))
|
|
27
|
+
const timeoutMs = positiveInt(argValue("--timeout-ms"), 20 * 60_000)
|
|
28
|
+
const idleTimeoutMs = positiveInt(argValue("--idle-timeout-ms"), 5 * 60_000)
|
|
29
|
+
const heartbeatMs = positiveInt(argValue("--heartbeat-ms"), 30_000)
|
|
30
|
+
const onlyLong = has("--long-only")
|
|
31
|
+
const onlyLive = has("--standard-only")
|
|
32
|
+
const onlyPolyglot = has("--polyglot-only")
|
|
33
|
+
const withoutPolyglot = has("--without-polyglot")
|
|
34
|
+
const requireConfidence = has("--require-confidence")
|
|
35
|
+
|
|
36
|
+
if (!model) {
|
|
37
|
+
console.error("Usage: node scripts/eval-matrix.mjs --model provider/model [--trials 3] [--auth current|env-only] [--variant high] [--without-polyglot|--long-only|--standard-only|--polyglot-only]")
|
|
38
|
+
process.exit(2)
|
|
39
|
+
}
|
|
40
|
+
const exclusiveCount = [onlyLong, onlyLive, onlyPolyglot].filter(Boolean).length
|
|
41
|
+
if (exclusiveCount > 1) {
|
|
42
|
+
console.error("--long-only, --standard-only and --polyglot-only are mutually exclusive")
|
|
43
|
+
process.exit(2)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
await mkdir(outputDir, { recursive: true })
|
|
47
|
+
const suites = onlyLong
|
|
48
|
+
? ["long"]
|
|
49
|
+
: onlyLive
|
|
50
|
+
? ["live"]
|
|
51
|
+
: onlyPolyglot
|
|
52
|
+
? ["polyglot"]
|
|
53
|
+
: withoutPolyglot
|
|
54
|
+
? ["long", "live"]
|
|
55
|
+
: ["long", "live", "polyglot"]
|
|
56
|
+
const startedAt = new Date().toISOString()
|
|
57
|
+
const before = new Set(await readdir(outputDir).catch(() => []))
|
|
58
|
+
|
|
59
|
+
for (const suite of suites) {
|
|
60
|
+
const command = [
|
|
61
|
+
path.join(root, "scripts", "eval-live.mjs"),
|
|
62
|
+
"--suite", suite,
|
|
63
|
+
"--model", model,
|
|
64
|
+
"--mode", "both",
|
|
65
|
+
"--trials", String(trials),
|
|
66
|
+
"--auth", auth,
|
|
67
|
+
"--output-dir", outputDir,
|
|
68
|
+
"--timeout-ms", String(timeoutMs),
|
|
69
|
+
"--idle-timeout-ms", String(idleTimeoutMs),
|
|
70
|
+
"--heartbeat-ms", String(heartbeatMs),
|
|
71
|
+
]
|
|
72
|
+
if (variant) command.push("--variant", variant)
|
|
73
|
+
|
|
74
|
+
console.log("\n[matrix] Running " + suite + " suite: " + trials + " trial(s) per task per mode")
|
|
75
|
+
const result = spawnSync(process.execPath, command, { cwd: process.cwd(), stdio: "inherit" })
|
|
76
|
+
if ((result.status ?? 1) !== 0) {
|
|
77
|
+
console.error("[matrix] " + suite + " suite failed with exit code " + (result.status ?? 1))
|
|
78
|
+
process.exit(result.status ?? 1)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const after = await readdir(outputDir)
|
|
83
|
+
const created = after
|
|
84
|
+
.filter((name) => name.endsWith(".json") && !before.has(name))
|
|
85
|
+
.sort()
|
|
86
|
+
|
|
87
|
+
const runs = []
|
|
88
|
+
const results = []
|
|
89
|
+
for (const name of created) {
|
|
90
|
+
const file = path.join(outputDir, name)
|
|
91
|
+
const payload = JSON.parse(await readFile(file, "utf8"))
|
|
92
|
+
if (!suites.includes(payload.suite) || payload.model !== model) continue
|
|
93
|
+
runs.push({
|
|
94
|
+
file: name,
|
|
95
|
+
suite: payload.suite,
|
|
96
|
+
suiteVersion: payload.suiteVersion,
|
|
97
|
+
trials: payload.trials,
|
|
98
|
+
results: payload.results?.length || 0,
|
|
99
|
+
})
|
|
100
|
+
results.push(...(payload.results || []).map((item) => ({ ...item, suite: payload.suite })))
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const expectedPerMode = suites.reduce((sum, suite) => {
|
|
104
|
+
if (suite === "long") return sum + 5 * trials
|
|
105
|
+
if (suite === "live") return sum + 20 * trials
|
|
106
|
+
if (suite === "polyglot") return sum + 8 * trials
|
|
107
|
+
return sum
|
|
108
|
+
}, 0)
|
|
109
|
+
const baselineCount = results.filter((item) => item.mode === "baseline").length
|
|
110
|
+
const uesCount = results.filter((item) => item.mode === "ues").length
|
|
111
|
+
const coverageComplete = baselineCount === expectedPerMode && uesCount === expectedPerMode
|
|
112
|
+
const summary = summarizeEvalResults(results)
|
|
113
|
+
const confidence = pairedBenchmarkConfidence(results)
|
|
114
|
+
|
|
115
|
+
const report = {
|
|
116
|
+
schemaVersion: 1,
|
|
117
|
+
kind: "ues-benchmark-matrix",
|
|
118
|
+
startedAt,
|
|
119
|
+
finishedAt: new Date().toISOString(),
|
|
120
|
+
model,
|
|
121
|
+
variant: variant || null,
|
|
122
|
+
trials,
|
|
123
|
+
auth,
|
|
124
|
+
suites,
|
|
125
|
+
expectedPerMode,
|
|
126
|
+
baselineCount,
|
|
127
|
+
uesCount,
|
|
128
|
+
coverageComplete,
|
|
129
|
+
runs,
|
|
130
|
+
pairedResults: results.map((item) => ({
|
|
131
|
+
suite: item.suite || null,
|
|
132
|
+
task: item.task,
|
|
133
|
+
trial: item.trial,
|
|
134
|
+
mode: item.mode,
|
|
135
|
+
passed: item.passed === true,
|
|
136
|
+
durationMs: item.durationMs ?? null,
|
|
137
|
+
telemetry: item.telemetry?.costSamples > 0 ? { cost: item.telemetry.cost } : {},
|
|
138
|
+
})),
|
|
139
|
+
summary,
|
|
140
|
+
confidence,
|
|
141
|
+
}
|
|
142
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, "-")
|
|
143
|
+
const reportFile = path.join(outputDir, "matrix-summary-" + stamp + ".json")
|
|
144
|
+
await writeFile(reportFile, JSON.stringify(report, null, 2) + "\n", "utf8")
|
|
145
|
+
|
|
146
|
+
console.log("\n[matrix] Benchmark matrix summary")
|
|
147
|
+
console.log("- baseline: " + (summary.modes.baseline?.passed || 0) + "/" + (summary.modes.baseline?.total || 0))
|
|
148
|
+
console.log("- UES: " + (summary.modes.ues?.passed || 0) + "/" + (summary.modes.ues?.total || 0))
|
|
149
|
+
console.log("- pass-rate delta: " + (summary.passRateDelta == null ? "n/a" : (summary.passRateDelta * 100).toFixed(1) + " pp"))
|
|
150
|
+
console.log("- coverage: " + (coverageComplete ? "COMPLETE" : "INCOMPLETE"))
|
|
151
|
+
console.log("- paired confidence: " + (confidence.promotionEligible ? "SUPPORTED" : "NOT YET SUPPORTED") + " (pairs=" + confidence.pairs + ", p=" + confidence.pValue.toFixed(4) + ")")
|
|
152
|
+
console.log("- confidence gate: " + (requireConfidence ? "REQUIRED" : "report-only"))
|
|
153
|
+
console.log("- report: " + reportFile)
|
|
154
|
+
|
|
155
|
+
if (!coverageComplete || (requireConfidence && !confidence.promotionEligible)) process.exitCode = 1
|
|
@@ -105,7 +105,7 @@ try {
|
|
|
105
105
|
assert.ok(existsSync(routerPlugin), "v2 router plugin was not installed from packed package")
|
|
106
106
|
assert.ok(existsSync(path.join(configDir, "plugins", "ues-router", "router.js")), "v2 router helper was not installed from packed package")
|
|
107
107
|
assert.ok(existsSync(path.join(configDir, "plugins", "ues-router", "safety.js")), "v2 router safety gate was not installed from packed package")
|
|
108
|
-
assert.ok(existsSync(path.join(configDir, "plugins", "ues-router", "capabilities.js")), "
|
|
108
|
+
assert.ok(existsSync(path.join(configDir, "plugins", "ues-router", "capabilities.js")), "v8 router capability probe was not installed from packed package")
|
|
109
109
|
const routerSource = await readFile(routerPlugin, "utf8")
|
|
110
110
|
assert.match(routerSource, /name: "dispatch_task"/)
|
|
111
111
|
assert.match(routerSource, /ctx\.session\.create/)
|
|
@@ -113,12 +113,15 @@ try {
|
|
|
113
113
|
assert.match(routerSource, /ctx\.session\.switchModel/)
|
|
114
114
|
assert.match(routerSource, /name: "capabilities"/)
|
|
115
115
|
assert.match(routerSource, /name: "task_policy"/)
|
|
116
|
+
assert.match(routerSource, /name: "cancel_task"/)
|
|
117
|
+
assert.match(routerSource, /name: "recover_task"/)
|
|
118
|
+
assert.match(routerSource, /ctx\.session\.interrupt/)
|
|
116
119
|
const reviewer = await readFile(path.join(configDir, "agents", "ues-reviewer.md"), "utf8")
|
|
117
120
|
assert.match(reviewer, /permissions:/)
|
|
118
121
|
assert.doesNotMatch(reviewer, /^permission:/m)
|
|
119
122
|
|
|
120
123
|
for (const name of ["ues-codebase-mapper.md", "ues-plan-checker.md", "ues-executor.md", "ues-integration-verifier.md"]) {
|
|
121
|
-
assert.ok(existsSync(path.join(configDir, "agents", name)), "missing packed
|
|
124
|
+
assert.ok(existsSync(path.join(configDir, "agents", name)), "missing packed V8 subagent " + name)
|
|
122
125
|
}
|
|
123
126
|
const executor = await readFile(path.join(configDir, "agents", "ues-executor.md"), "utf8")
|
|
124
127
|
assert.match(executor, /permissions:/)
|
|
@@ -136,7 +139,7 @@ try {
|
|
|
136
139
|
const planFile = path.join(temp, "PLAN.json")
|
|
137
140
|
await writeFile(planFile, JSON.stringify({
|
|
138
141
|
schemaVersion: 1,
|
|
139
|
-
goal: "Packed
|
|
142
|
+
goal: "Packed V8 smoke",
|
|
140
143
|
tasks: [{
|
|
141
144
|
id: "T1",
|
|
142
145
|
title: "Smoke",
|
|
@@ -157,12 +160,24 @@ try {
|
|
|
157
160
|
requireSuccess(graph, "ocskill task-graph from packed copy")
|
|
158
161
|
assert.match(graph.stdout, /"valid": true/)
|
|
159
162
|
|
|
160
|
-
const workInit = spawnSync(process.execPath, [cli, "work", "init", "packed-smoke", temp, "--goal", "Packed
|
|
163
|
+
const workInit = spawnSync(process.execPath, [cli, "work", "init", "packed-smoke", temp, "--goal", "Packed V8 work smoke"], {
|
|
161
164
|
cwd: temp,
|
|
162
165
|
env,
|
|
163
166
|
encoding: "utf8",
|
|
164
167
|
})
|
|
165
168
|
requireSuccess(workInit, "ocskill work init from packed copy")
|
|
169
|
+
assert.ok(
|
|
170
|
+
existsSync(path.join(temp, ".ues-work", "packed-smoke", "EVENTS.jsonl")),
|
|
171
|
+
"packed V8 work item did not create EVENTS.jsonl",
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
const workEvents = spawnSync(process.execPath, [cli, "work", "events", "packed-smoke", temp], {
|
|
175
|
+
cwd: temp,
|
|
176
|
+
env,
|
|
177
|
+
encoding: "utf8",
|
|
178
|
+
})
|
|
179
|
+
requireSuccess(workEvents, "ocskill work events from packed copy")
|
|
180
|
+
assert.match(workEvents.stdout, /"work\.init"/)
|
|
166
181
|
|
|
167
182
|
const workPlan = spawnSync(process.execPath, [cli, "work", "plan", "packed-smoke", planFile, temp], {
|
|
168
183
|
cwd: temp,
|
|
@@ -266,6 +281,125 @@ try {
|
|
|
266
281
|
requireSuccess(workFinalize, "ocskill work finalize from packed copy")
|
|
267
282
|
assert.match(workFinalize.stdout, /"status": "completed"/)
|
|
268
283
|
|
|
284
|
+
const strictPlanFile = path.join(temp, "STRICT-PLAN.json")
|
|
285
|
+
await writeFile(strictPlanFile, JSON.stringify({
|
|
286
|
+
schemaVersion: 1,
|
|
287
|
+
goal: "Packed V8 strict evidence smoke",
|
|
288
|
+
tasks: [
|
|
289
|
+
{
|
|
290
|
+
id: "S1",
|
|
291
|
+
title: "Strict one",
|
|
292
|
+
summary: "Exercise structured plan/task evidence",
|
|
293
|
+
files: { modify: ["src/one.js"] },
|
|
294
|
+
dependsOn: [],
|
|
295
|
+
acceptance: ["S1 is verified"],
|
|
296
|
+
verification: ["node --version"],
|
|
297
|
+
risk: "medium",
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
id: "S2",
|
|
301
|
+
title: "Strict two",
|
|
302
|
+
summary: "Exercise structured integration evidence",
|
|
303
|
+
files: { modify: ["src/two.js"] },
|
|
304
|
+
dependsOn: ["S1"],
|
|
305
|
+
acceptance: ["S2 is verified"],
|
|
306
|
+
verification: ["node --version"],
|
|
307
|
+
risk: "medium",
|
|
308
|
+
},
|
|
309
|
+
],
|
|
310
|
+
}, null, 2) + "\n", "utf8")
|
|
311
|
+
|
|
312
|
+
requireSuccess(
|
|
313
|
+
spawnSync(process.execPath, [cli, "work", "init", "packed-strict", temp, "--goal", "Packed V8 strict evidence smoke"], {
|
|
314
|
+
cwd: temp, env, encoding: "utf8",
|
|
315
|
+
}),
|
|
316
|
+
"strict work init from packed copy",
|
|
317
|
+
)
|
|
318
|
+
requireSuccess(
|
|
319
|
+
spawnSync(process.execPath, [cli, "work", "plan", "packed-strict", strictPlanFile, temp], {
|
|
320
|
+
cwd: temp, env, encoding: "utf8",
|
|
321
|
+
}),
|
|
322
|
+
"strict work plan from packed copy",
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
const plainStrictApproval = spawnSync(process.execPath, [
|
|
326
|
+
cli, "work", "approve-plan", "packed-strict", temp, "--evidence", "plain PASS",
|
|
327
|
+
], { cwd: temp, env, encoding: "utf8" })
|
|
328
|
+
assert.notEqual(plainStrictApproval.status, 0)
|
|
329
|
+
assert.match(plainStrictApproval.stderr, /structured plan-verification receipt/)
|
|
330
|
+
|
|
331
|
+
const strictPlanReceipt = path.join(temp, ".ues-work", "packed-strict", "reports", "plan-receipt.json")
|
|
332
|
+
requireSuccess(
|
|
333
|
+
spawnSync(process.execPath, [
|
|
334
|
+
cli, "work", "gate-receipt", "packed-strict", "plan", temp,
|
|
335
|
+
"--verifier", "ues-plan-checker",
|
|
336
|
+
"--evidence", "strict plan PASS",
|
|
337
|
+
"--out", strictPlanReceipt,
|
|
338
|
+
], { cwd: temp, env, encoding: "utf8" }),
|
|
339
|
+
"strict plan receipt from packed copy",
|
|
340
|
+
)
|
|
341
|
+
requireSuccess(
|
|
342
|
+
spawnSync(process.execPath, [
|
|
343
|
+
cli, "work", "approve-plan", "packed-strict", temp,
|
|
344
|
+
"--evidence", "strict plan PASS",
|
|
345
|
+
"--receipt-file", strictPlanReceipt,
|
|
346
|
+
], { cwd: temp, env, encoding: "utf8" }),
|
|
347
|
+
"strict plan approval from packed copy",
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
for (const taskID of ["S1", "S2"]) {
|
|
351
|
+
const strictStart = spawnSync(process.execPath, [cli, "work", "start", "packed-strict", taskID, temp], {
|
|
352
|
+
cwd: temp, env, encoding: "utf8",
|
|
353
|
+
})
|
|
354
|
+
requireSuccess(strictStart, "strict " + taskID + " start from packed copy")
|
|
355
|
+
const strictStarted = JSON.parse(strictStart.stdout)
|
|
356
|
+
const runId = strictStarted.record.runId
|
|
357
|
+
|
|
358
|
+
requireSuccess(
|
|
359
|
+
spawnSync(process.execPath, [
|
|
360
|
+
cli, "work", "verify-command", "packed-strict", taskID, temp,
|
|
361
|
+
"--run-id", runId,
|
|
362
|
+
"--", process.execPath, "--version",
|
|
363
|
+
], { cwd: temp, env, encoding: "utf8" }),
|
|
364
|
+
"strict " + taskID + " verification from packed copy",
|
|
365
|
+
)
|
|
366
|
+
requireSuccess(
|
|
367
|
+
spawnSync(process.execPath, [
|
|
368
|
+
cli, "work", "complete", "packed-strict", taskID, temp,
|
|
369
|
+
"--run-id", runId,
|
|
370
|
+
"--evidence", taskID + " verification PASS",
|
|
371
|
+
], { cwd: temp, env, encoding: "utf8" }),
|
|
372
|
+
"strict " + taskID + " completion from packed copy",
|
|
373
|
+
)
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const strictIntegrationReceipt = path.join(temp, ".ues-work", "packed-strict", "reports", "integration-receipt.json")
|
|
377
|
+
requireSuccess(
|
|
378
|
+
spawnSync(process.execPath, [
|
|
379
|
+
cli, "work", "gate-receipt", "packed-strict", "integration", temp,
|
|
380
|
+
"--verifier", "ues-integration-verifier",
|
|
381
|
+
"--verdict", "PASS",
|
|
382
|
+
"--evidence", "strict integration PASS",
|
|
383
|
+
"--out", strictIntegrationReceipt,
|
|
384
|
+
], { cwd: temp, env, encoding: "utf8" }),
|
|
385
|
+
"strict integration receipt from packed copy",
|
|
386
|
+
)
|
|
387
|
+
requireSuccess(
|
|
388
|
+
spawnSync(process.execPath, [
|
|
389
|
+
cli, "work", "verify-integration", "packed-strict", temp,
|
|
390
|
+
"--verdict", "PASS",
|
|
391
|
+
"--evidence", "strict integration PASS",
|
|
392
|
+
"--receipt-file", strictIntegrationReceipt,
|
|
393
|
+
], { cwd: temp, env, encoding: "utf8" }),
|
|
394
|
+
"strict integration verification from packed copy",
|
|
395
|
+
)
|
|
396
|
+
const strictFinalize = spawnSync(process.execPath, [
|
|
397
|
+
cli, "work", "finalize", "packed-strict", temp,
|
|
398
|
+
"--evidence", "strict final acceptance PASS",
|
|
399
|
+
], { cwd: temp, env, encoding: "utf8" })
|
|
400
|
+
requireSuccess(strictFinalize, "strict finalization from packed copy")
|
|
401
|
+
assert.match(strictFinalize.stdout, /"status": "completed"/)
|
|
402
|
+
|
|
269
403
|
const adaptivePolicy = spawnSync(process.execPath, [
|
|
270
404
|
cli, "task-policy",
|
|
271
405
|
"Refactor the entire repository authentication schema migration and public API contracts",
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import assert from "node:assert/strict"
|
|
2
|
+
import { existsSync } from "node:fs"
|
|
3
|
+
import { mkdir, mkdtemp, readFile, readdir, realpath, rm } from "node:fs/promises"
|
|
4
|
+
import { spawnSync } from "node:child_process"
|
|
5
|
+
import os from "node:os"
|
|
6
|
+
import path from "node:path"
|
|
7
|
+
import { fileURLToPath } from "node:url"
|
|
8
|
+
|
|
9
|
+
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
|
|
10
|
+
const packageJson = JSON.parse(await readFile(path.join(repoRoot, "package.json"), "utf8"))
|
|
11
|
+
const packageName = packageJson.name
|
|
12
|
+
|
|
13
|
+
function runNpm(args, options = {}) {
|
|
14
|
+
const common = {
|
|
15
|
+
cwd: options.cwd ?? repoRoot,
|
|
16
|
+
env: options.env ?? process.env,
|
|
17
|
+
encoding: "utf8",
|
|
18
|
+
}
|
|
19
|
+
const npmExecPath = process.env.npm_execpath
|
|
20
|
+
if (npmExecPath && existsSync(npmExecPath)) {
|
|
21
|
+
return spawnSync(process.execPath, [npmExecPath, ...args], common)
|
|
22
|
+
}
|
|
23
|
+
return spawnSync("npm", args, { ...common, shell: process.platform === "win32" })
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function requireSuccess(result, label) {
|
|
27
|
+
if (result.status === 0) return
|
|
28
|
+
throw new Error(
|
|
29
|
+
label + " failed with exit code " + (result.status ?? "unknown") + "\n" +
|
|
30
|
+
[result.stdout, result.stderr].filter(Boolean).join("\n"),
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const temp = await mkdtemp(path.join(os.tmpdir(), "ocskill-plain-install-"))
|
|
35
|
+
const packDir = path.join(temp, "pack")
|
|
36
|
+
const prefix = path.join(temp, "prefix")
|
|
37
|
+
const configDir = path.join(temp, "opencode")
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
await mkdir(packDir, { recursive: true })
|
|
41
|
+
const pack = runNpm(["pack", "--pack-destination", packDir])
|
|
42
|
+
requireSuccess(pack, "npm pack")
|
|
43
|
+
const tarballs = (await readdir(packDir)).filter((name) => name.endsWith(".tgz"))
|
|
44
|
+
assert.equal(tarballs.length, 1)
|
|
45
|
+
|
|
46
|
+
const npmVersionRun = runNpm(["--version"], { cwd: temp })
|
|
47
|
+
requireSuccess(npmVersionRun, "npm --version")
|
|
48
|
+
const npmVersion = npmVersionRun.stdout.trim()
|
|
49
|
+
const npmMajor = Number.parseInt(npmVersion.split(".")[0], 10)
|
|
50
|
+
|
|
51
|
+
// Intentionally mirrors the user's exact install shape: no --allow-scripts.
|
|
52
|
+
const install = runNpm(["install", "-g", tarballs.map((name) => path.join(packDir, name))[0], "--prefix", prefix], {
|
|
53
|
+
cwd: temp,
|
|
54
|
+
env: { ...process.env, OPENCODE_CONFIG_DIR: configDir, UES_OPENCODE_MAJOR: "2" },
|
|
55
|
+
})
|
|
56
|
+
requireSuccess(install, "plain global install")
|
|
57
|
+
|
|
58
|
+
const root = runNpm(["root", "-g", "--prefix", prefix], { cwd: temp })
|
|
59
|
+
requireSuccess(root, "npm root -g")
|
|
60
|
+
const packageDir = path.join(root.stdout.trim(), ...packageName.split("/"))
|
|
61
|
+
assert.equal((await realpath(packageDir)).toLowerCase() === (await realpath(repoRoot)).toLowerCase(), false)
|
|
62
|
+
|
|
63
|
+
const cli = path.join(packageDir, "bin", "ocskill.mjs")
|
|
64
|
+
assert.ok(existsSync(cli), "plain install did not install the ocskill CLI")
|
|
65
|
+
|
|
66
|
+
const stateFile = path.join(configDir, ".ues", "state.json")
|
|
67
|
+
const autoSynced = existsSync(stateFile)
|
|
68
|
+
assert.equal(
|
|
69
|
+
autoSynced,
|
|
70
|
+
true,
|
|
71
|
+
"plain npm install installed the CLI but did not auto-sync OpenCode resources; one-command installation is not release-safe",
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
const state = JSON.parse(await readFile(stateFile, "utf8"))
|
|
75
|
+
assert.equal(state.package, packageName)
|
|
76
|
+
assert.ok(state.skills.length >= 39)
|
|
77
|
+
assert.ok(state.commands.length >= 11)
|
|
78
|
+
assert.ok(state.agents.length >= 10)
|
|
79
|
+
|
|
80
|
+
console.log(
|
|
81
|
+
"Plain npm install compatibility smoke passed for " + packageName + "@" + packageJson.version +
|
|
82
|
+
": npm " + npmVersion + ", lifecycle auto-sync=" + autoSynced +
|
|
83
|
+
", final resources=" + state.skills.length + "/" + state.commands.length + "/" + state.agents.length + ".",
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
if (Number.isFinite(npmMajor) && npmMajor >= 11) {
|
|
87
|
+
console.warn("[smoke] npm 11+ completed the one-command install and resource auto-sync contract.")
|
|
88
|
+
}
|
|
89
|
+
} finally {
|
|
90
|
+
await rm(temp, { recursive: true, force: true })
|
|
91
|
+
}
|
|
@@ -8,8 +8,8 @@ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
|
|
|
8
8
|
const args = process.argv.slice(2)
|
|
9
9
|
const suiteIndex = args.indexOf("--suite")
|
|
10
10
|
const suiteName = suiteIndex >= 0 ? args[suiteIndex + 1] : "live"
|
|
11
|
-
if (!["live", "long"].includes(suiteName)) {
|
|
12
|
-
console.error("--suite must be live or
|
|
11
|
+
if (!["live", "long", "polyglot"].includes(suiteName)) {
|
|
12
|
+
console.error("--suite must be live, long or polyglot")
|
|
13
13
|
process.exit(2)
|
|
14
14
|
}
|
|
15
15
|
const suiteRoot = path.join(root, "evals", suiteName)
|
|
@@ -17,7 +17,7 @@ const suite = JSON.parse(await readFile(path.join(suiteRoot, "tasks.json"), "utf
|
|
|
17
17
|
const errors = []
|
|
18
18
|
const ids = new Set()
|
|
19
19
|
|
|
20
|
-
const minimumTasks = suiteName === "long" ? 5 : 20
|
|
20
|
+
const minimumTasks = suiteName === "long" ? 5 : suiteName === "polyglot" ? 8 : 20
|
|
21
21
|
if (!Array.isArray(suite.tasks) || suite.tasks.length < minimumTasks) {
|
|
22
22
|
errors.push(suiteName + " eval suite must contain at least " + minimumTasks + " tasks")
|
|
23
23
|
}
|