opencode-agent-skill 15.1.0 → 15.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.
Files changed (37) hide show
  1. package/README.md +3 -3
  2. package/docs/V15-MANAGED-RUNTIME.md +18 -0
  3. package/global-config/agents/verifier.md +6 -2
  4. package/lib/affected-tests.mjs +21 -4
  5. package/lib/capability-fabric.mjs +107 -48
  6. package/lib/code-intelligence/index.mjs +3 -15
  7. package/lib/code-intelligence/lsp-pool.mjs +694 -0
  8. package/lib/code-intelligence/lsp-provider.mjs +160 -20
  9. package/lib/compaction-resume-guard.mjs +76 -4
  10. package/lib/completion-auditor.mjs +20 -0
  11. package/lib/context-manifest.mjs +38 -21
  12. package/lib/decision-policy.mjs +40 -2
  13. package/lib/evidence-store.mjs +121 -31
  14. package/lib/executable-probe.mjs +69 -0
  15. package/lib/hierarchical-context.mjs +31 -3
  16. package/lib/learning-engine.mjs +164 -65
  17. package/lib/memory-engine.mjs +163 -86
  18. package/lib/model-config.mjs +86 -7
  19. package/lib/performance-fabric.mjs +92 -0
  20. package/lib/permission-policy.mjs +232 -0
  21. package/lib/pi-rpc-pool.mjs +170 -5
  22. package/lib/provider-recovery.mjs +51 -0
  23. package/lib/repo-graph.mjs +38 -5
  24. package/lib/runtime-events.mjs +31 -10
  25. package/lib/semantic-index.mjs +67 -20
  26. package/lib/skill-compiler.mjs +84 -18
  27. package/lib/task-policy.mjs +80 -7
  28. package/lib/trajectory.mjs +25 -1
  29. package/lib/untrusted-output.mjs +106 -0
  30. package/package.json +8 -6
  31. package/pi/extensions/ues-child-runtime.ts +78 -3
  32. package/pi/extensions/ues.ts +695 -81
  33. package/scripts/benchmark-lsp-pool.mjs +128 -0
  34. package/scripts/check-release-consistency.mjs +16 -4
  35. package/scripts/check-source-integrity.mjs +60 -1
  36. package/scripts/run-test-suite.mjs +143 -0
  37. package/scripts/smoke-package-closure.mjs +4 -0
@@ -0,0 +1,128 @@
1
+ import { performance } from "node:perf_hooks"
2
+ import { mkdtemp, rm, stat, writeFile } from "node:fs/promises"
3
+ import os from "node:os"
4
+ import path from "node:path"
5
+ import {
6
+ lspPoolStatus,
7
+ resetLspPoolMetrics,
8
+ shutdownLspPool,
9
+ withManagedLspSession,
10
+ } from "../lib/code-intelligence/lsp-pool.mjs"
11
+
12
+ const MOCK_SERVER = `
13
+ let buffer = Buffer.alloc(0)
14
+ function encode(payload) {
15
+ const body = Buffer.from(JSON.stringify(payload), "utf8")
16
+ return Buffer.concat([Buffer.from("Content-Length: " + body.length + "\\r\\n\\r\\n", "ascii"), body])
17
+ }
18
+ function send(payload) { process.stdout.write(encode(payload)) }
19
+ function dispatch(message) {
20
+ const method = String(message?.method || "")
21
+ if (message?.id != null) {
22
+ if (method === "initialize") {
23
+ send({ jsonrpc: "2.0", id: message.id, result: { capabilities: { documentSymbolProvider: true } } })
24
+ return
25
+ }
26
+ if (method === "textDocument/documentSymbol") {
27
+ send({ jsonrpc: "2.0", id: message.id, result: [{ name: "benchSymbol", kind: 12, range: null, selectionRange: null }] })
28
+ return
29
+ }
30
+ send({ jsonrpc: "2.0", id: message.id, result: null })
31
+ return
32
+ }
33
+ if (method === "exit") process.exit(0)
34
+ }
35
+ function parse() {
36
+ while (true) {
37
+ const headerEnd = buffer.indexOf("\\r\\n\\r\\n")
38
+ if (headerEnd < 0) return
39
+ const header = buffer.subarray(0, headerEnd).toString("ascii")
40
+ const match = header.match(/Content-Length:\\s*(\\d+)/i)
41
+ if (!match) { buffer = buffer.subarray(headerEnd + 4); continue }
42
+ const length = Number(match[1])
43
+ const start = headerEnd + 4
44
+ if (buffer.length < start + length) return
45
+ const body = buffer.subarray(start, start + length).toString("utf8")
46
+ buffer = buffer.subarray(start + length)
47
+ try { dispatch(JSON.parse(body)) } catch {}
48
+ }
49
+ }
50
+ process.stdin.on("data", (chunk) => {
51
+ buffer = Buffer.concat([buffer, Buffer.from(chunk)])
52
+ parse()
53
+ })
54
+ `
55
+
56
+ function median(values) {
57
+ const sorted = [...values].sort((a, b) => a - b)
58
+ const middle = Math.floor(sorted.length / 2)
59
+ return sorted.length % 2 ? sorted[middle] : (sorted[middle - 1] + sorted[middle]) / 2
60
+ }
61
+
62
+ async function main() {
63
+ const root = await mkdtemp(path.join(os.tmpdir(), "ues-lsp-bench-"))
64
+ try {
65
+ resetLspPoolMetrics()
66
+ const server = path.join(root, "mock-lsp.mjs")
67
+ const source = path.join(root, "demo.ts")
68
+ await writeFile(server, MOCK_SERVER, "utf8")
69
+ await writeFile(source, "export const benchmarkValue = 1\n", "utf8")
70
+
71
+ const provider = {
72
+ id: "typescript-benchmark",
73
+ command: process.execPath,
74
+ args: [server],
75
+ languageId: "typescript",
76
+ }
77
+ const target = { base: root, file: source, info: await stat(source) }
78
+ const run = async () => {
79
+ const started = performance.now()
80
+ const result = await withManagedLspSession(
81
+ target,
82
+ provider,
83
+ { maxServers: 1, maxPerWorkspace: 1, timeoutMs: 2000, startupTimeoutMs: 3000 },
84
+ async (session) => session.request("textDocument/documentSymbol", {
85
+ textDocument: { uri: session.uri },
86
+ }),
87
+ )
88
+ if (!result.ok) throw new Error("LSP benchmark failed: " + String(result.reason || result.error || "unknown"))
89
+ return {
90
+ totalMs: performance.now() - started,
91
+ poolHit: result.meta.poolHit,
92
+ coldStartMs: result.meta.coldStartMs,
93
+ operationDurationMs: result.meta.operationDurationMs,
94
+ }
95
+ }
96
+
97
+ const cold = await run()
98
+ const warm = []
99
+ for (let index = 0; index < 8; index += 1) warm.push(await run())
100
+ const warmTotals = warm.map((item) => item.totalMs)
101
+ const status = lspPoolStatus()
102
+
103
+ console.log(JSON.stringify({
104
+ schemaVersion: 1,
105
+ kind: "ues-lsp-pool-benchmark",
106
+ node: process.version,
107
+ platform: process.platform,
108
+ cold: {
109
+ totalMs: Number(cold.totalMs.toFixed(3)),
110
+ coldStartMs: cold.coldStartMs,
111
+ operationDurationMs: cold.operationDurationMs,
112
+ },
113
+ warm: {
114
+ samples: warm.length,
115
+ medianTotalMs: Number(median(warmTotals).toFixed(3)),
116
+ minTotalMs: Number(Math.min(...warmTotals).toFixed(3)),
117
+ maxTotalMs: Number(Math.max(...warmTotals).toFixed(3)),
118
+ allPoolHits: warm.every((item) => item.poolHit === true),
119
+ },
120
+ pool: status.metrics,
121
+ }, null, 2))
122
+ } finally {
123
+ await shutdownLspPool(root)
124
+ await rm(root, { recursive: true, force: true })
125
+ }
126
+ }
127
+
128
+ await main()
@@ -142,8 +142,20 @@ export function checkReleaseConsistency(root = DEFAULT_ROOT) {
142
142
 
143
143
  if (pkg) {
144
144
  const scripts = pkg.scripts || {}
145
- if (scripts.test !== "node --test") errors.push("package.json: npm test must run portable full Node test discovery")
146
- if (scripts["test:pi"] !== "node --test test/pi-package.test.mjs") errors.push("package.json: missing focused test:pi script")
145
+ if (scripts.test !== "node scripts/run-test-suite.mjs") {
146
+ errors.push("package.json: npm test must run the bounded per-file test runner")
147
+ }
148
+ const focusedPi = String(scripts["test:pi"] || "").trim().split(/\s+/).filter(Boolean)
149
+ if (
150
+ focusedPi[0] !== "node" ||
151
+ focusedPi[1] !== "scripts/run-test-suite.mjs" ||
152
+ !focusedPi.includes("test/pi-package.test.mjs")
153
+ ) {
154
+ errors.push("package.json: missing bounded focused test:pi script")
155
+ }
156
+ if (scripts["test:node"] !== "node --test") {
157
+ errors.push("package.json: test:node must preserve raw Node test discovery for diagnosis")
158
+ }
147
159
  if (scripts["docs:check"] !== "node scripts/check-release-consistency.mjs") errors.push("package.json: missing docs:check release-consistency script")
148
160
  if (scripts["release:check-tag"] !== "node scripts/check-release-tag.mjs") errors.push("package.json: missing release:check-tag script")
149
161
  if (scripts["eval:pi"] !== "node scripts/eval-pi.mjs") errors.push("package.json: missing Pi-native eval:pi script")
@@ -160,10 +172,10 @@ export function checkReleaseConsistency(root = DEFAULT_ROOT) {
160
172
  ]
161
173
  if (
162
174
  focusedV15[0] !== "node" ||
163
- focusedV15[1] !== "--test" ||
175
+ focusedV15[1] !== "scripts/run-test-suite.mjs" ||
164
176
  !requiredFocusedV15Tests.every((file) => focusedV15.includes(file))
165
177
  ) {
166
- errors.push("package.json: focused eval:v15 must run the current V15 runtime, disk-safety, intelligence and Pi-package regression set")
178
+ errors.push("package.json: focused eval:v15 must use the bounded runner and include the current V15 runtime, disk-safety, intelligence and Pi-package regression set")
167
179
  }
168
180
  if (!String(scripts.ci || "").includes("npm run integrity")) errors.push("package.json: ci must include source-integrity gate")
169
181
  if (scripts["runtime:exports"] !== "node scripts/check-runtime-exports.mjs") errors.push("package.json: missing runtime:exports import/export gate")
@@ -11,6 +11,12 @@ const CONTRACTS = [
11
11
  minBytes: 80_000,
12
12
  startsWith: "import { spawn }",
13
13
  required: [
14
+ "ues_code",
15
+ "UES Code Intelligence Lite",
16
+ "parent-lite",
17
+ "controllerStarted",
18
+ "childSpawned",
19
+ "shutdownLspPool",
14
20
  'name: "ues_cli"',
15
21
  'name: "ues_execute"',
16
22
  'name: "ues_dispatch"',
@@ -35,6 +41,18 @@ const CONTRACTS = [
35
41
  "void directControllerRunner",
36
42
  "UES_AUTO_ADMIT",
37
43
  "UES_PARENT_TOOL_NAMES",
44
+ "ALWAYS_ON_PARENT_TOOLS",
45
+ 'pi.on("agent_before_settle"',
46
+ "ues-parent-provider-recovery",
47
+ "parentRunToolCalls",
48
+ "parentProviderRecoveryConsecutive",
49
+ "parentProviderRecoveryTotal",
50
+ "parentProviderRecoveryPending",
51
+ "PARENT_PROVIDER_RECOVERY_MAX_CONSECUTIVE",
52
+ "PARENT_PROVIDER_RECOVERY_MAX_TOTAL",
53
+ "Do not restart the task and do not repeat tool calls that already completed",
54
+ 'new Set(["ues_code"])',
55
+ '!ALWAYS_ON_PARENT_TOOLS.has(toolName)',
38
56
  "pi.getActiveTools",
39
57
  "pi.setActiveTools",
40
58
  "deactivateParentUesTools",
@@ -118,6 +136,7 @@ const CONTRACTS = [
118
136
  'process.env.UES_CHILD_PROCESS !== "1"',
119
137
  "looksLikeLongRunningServiceCommand",
120
138
  "stopAllServices",
139
+ "shutdownLspPool",
121
140
  "applyAnchoredFileEdits",
122
141
  "diagnoseCode",
123
142
  "recordVerification",
@@ -402,7 +421,28 @@ const CONTRACTS = [
402
421
  file: "lib/code-intelligence/lsp-provider.mjs",
403
422
  minBytes: 5_000,
404
423
  startsWith: "import ",
405
- required: ["diagnoseCode", "lspProviderStatus", "publishDiagnostics"],
424
+ required: ["diagnoseCode", "lspProviderStatus", "lspPersistencePolicy", "short-lived-default", "pi-child-runtime", "publishDiagnostics", "withManagedLspSession", "fallbackFrom", "shutdownLspPool", "resolveTypeScriptTsserverFallback", "UES_TYPESCRIPT_TSSERVER_PATH", "initializationOptions", "fallbackPath", "resolveWindowsCommand"],
425
+ },
426
+ {
427
+ file: "lib/code-intelligence/lsp-pool.mjs",
428
+ minBytes: 12_000,
429
+ startsWith: "import ",
430
+ required: [
431
+ "withManagedLspSession",
432
+ "shutdownLspPool",
433
+ "lspPoolStatus",
434
+ "pool-capacity-busy",
435
+ "bounded-restart",
436
+ "config-changed",
437
+ "textDocument/didChange",
438
+ "UES_LSP_MAX_SERVERS",
439
+ "UES_LSP_IDLE_TTL_MS",
440
+ "resolveWindowsCommand",
441
+ "managed-lsp-request-rejected",
442
+ "initializationOptions",
443
+ "JSON.stringify(provider?.initializationOptions || null)",
444
+ ],
445
+ forbidden: ["\\nimport { resolveWindowsCommand }"],
406
446
  },
407
447
  {
408
448
  file: "lib/execution-contract.mjs",
@@ -657,6 +697,20 @@ const CONTRACTS = [
657
697
  ],
658
698
  },
659
699
 
700
+ {
701
+ file: "scripts/run-test-suite.mjs",
702
+ minBytes: 3_000,
703
+ startsWith: "import ",
704
+ required: [
705
+ "runSupervisedProcess",
706
+ "UES_TEST_FILE_TIMEOUT_MS",
707
+ "UES_TEST_CONCURRENCY",
708
+ "HANG/TIMEOUT",
709
+ "hardTimeoutMs: timeoutMs",
710
+ "UES_BOUNDED_TEST_RUNNER",
711
+ "Failing or leaking test files",
712
+ ],
713
+ },
660
714
  {
661
715
  file: "scripts/eval-pi.mjs",
662
716
  minBytes: 15_000,
@@ -702,6 +756,11 @@ for (const contract of CONTRACTS) {
702
756
  problems.push(`${contract.file}: missing integrity marker ${JSON.stringify(marker)}`)
703
757
  }
704
758
  }
759
+ for (const marker of contract.forbidden || []) {
760
+ if (source.includes(marker)) {
761
+ problems.push(`${contract.file}: forbidden integrity marker ${JSON.stringify(marker)}`)
762
+ }
763
+ }
705
764
  }
706
765
 
707
766
  assert.deepEqual(
@@ -0,0 +1,143 @@
1
+ import { readdir } from "node:fs/promises"
2
+ import os from "node:os"
3
+ import path from "node:path"
4
+ import { fileURLToPath } from "node:url"
5
+ import { runSupervisedProcess } from "../lib/process-supervisor.mjs"
6
+
7
+ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
8
+ const testRoot = path.join(root, "test")
9
+
10
+ function bounded(value, fallback, min, max) {
11
+ const parsed = Number(value)
12
+ if (!Number.isFinite(parsed)) return fallback
13
+ return Math.max(min, Math.min(max, Math.trunc(parsed)))
14
+ }
15
+
16
+ async function walk(dir) {
17
+ const entries = await readdir(dir, { withFileTypes: true })
18
+ const output = []
19
+ for (const entry of entries) {
20
+ const absolute = path.join(dir, entry.name)
21
+ if (entry.isDirectory()) output.push(...await walk(absolute))
22
+ else if (entry.isFile() && entry.name.endsWith(".test.mjs")) output.push(absolute)
23
+ }
24
+ return output
25
+ }
26
+
27
+ function relative(file) {
28
+ return path.relative(root, file).replaceAll("\\", "/")
29
+ }
30
+
31
+ function selectedFiles(allFiles) {
32
+ const positional = process.argv.slice(2).filter((arg) => !arg.startsWith("--"))
33
+ if (!positional.length) return allFiles
34
+ const requested = new Set(positional.map((item) => path.resolve(root, item)))
35
+ return allFiles.filter((file) => requested.has(path.resolve(file)))
36
+ }
37
+
38
+ function parseFlag(name, fallback) {
39
+ const direct = process.argv.find((arg) => arg.startsWith(name + "="))
40
+ if (!direct) return fallback
41
+ return direct.slice(name.length + 1)
42
+ }
43
+
44
+ const cpuDefault = Math.max(2, Math.min(6, os.availableParallelism?.() || os.cpus().length || 4))
45
+ const concurrency = bounded(
46
+ parseFlag("--concurrency", process.env.UES_TEST_CONCURRENCY),
47
+ cpuDefault,
48
+ 1,
49
+ 12,
50
+ )
51
+ const timeoutMs = bounded(
52
+ parseFlag("--timeout-ms", process.env.UES_TEST_FILE_TIMEOUT_MS),
53
+ 45_000,
54
+ 5_000,
55
+ 10 * 60_000,
56
+ )
57
+ const files = selectedFiles((await walk(testRoot)).sort((a, b) => relative(a).localeCompare(relative(b))))
58
+
59
+ if (!files.length) {
60
+ console.error("No matching test files.")
61
+ process.exitCode = 2
62
+ } else {
63
+ console.log(`UES bounded test runner: ${files.length} files; concurrency=${concurrency}; perFileTimeoutMs=${timeoutMs}`)
64
+
65
+ let cursor = 0
66
+ let passed = 0
67
+ const failures = []
68
+ const startedAt = Date.now()
69
+
70
+ async function worker(workerId) {
71
+ while (true) {
72
+ const index = cursor++
73
+ if (index >= files.length) return
74
+ const file = files[index]
75
+ const label = relative(file)
76
+ const ordinal = index + 1
77
+ console.log(`[${ordinal}/${files.length}] RUN ${label}`)
78
+
79
+ const result = await runSupervisedProcess(
80
+ process.execPath,
81
+ ["--test", file],
82
+ {
83
+ cwd: root,
84
+ hardTimeoutMs: timeoutMs,
85
+ idleTimeoutMs: 0,
86
+ killGraceMs: 500,
87
+ drainTimeoutMs: 2_000,
88
+ stdoutLimit: 8 * 1024 * 1024,
89
+ stderrLimit: 4 * 1024 * 1024,
90
+ env: {
91
+ ...process.env,
92
+ UES_BOUNDED_TEST_RUNNER: "1",
93
+ },
94
+ },
95
+ )
96
+
97
+ if (result.exitCode === 0 && !result.stopReason) {
98
+ passed += 1
99
+ console.log(`[${ordinal}/${files.length}] PASS ${label} (${result.durationMs}ms)`)
100
+ continue
101
+ }
102
+
103
+ const timedOut = result.stopReason === "hard-timeout"
104
+ const reason = timedOut
105
+ ? `HANG/TIMEOUT after ${timeoutMs}ms`
106
+ : result.stopReason
107
+ ? `STOPPED: ${result.stopReason}`
108
+ : `EXIT ${result.exitCode}`
109
+ failures.push({
110
+ file: label,
111
+ reason,
112
+ exitCode: result.exitCode,
113
+ stopReason: result.stopReason,
114
+ durationMs: result.durationMs,
115
+ })
116
+
117
+ console.error(`[${ordinal}/${files.length}] FAIL ${label}: ${reason}`)
118
+ const stdout = String(result.stdout || "").trim()
119
+ const stderr = String(result.stderr || "").trim()
120
+ if (stdout) console.error("\n--- stdout: " + label + " ---\n" + stdout.slice(-64_000))
121
+ if (stderr) console.error("\n--- stderr: " + label + " ---\n" + stderr.slice(-32_000))
122
+ }
123
+ }
124
+
125
+ await Promise.all(Array.from({ length: Math.min(concurrency, files.length) }, (_, index) => worker(index + 1)))
126
+
127
+ const durationMs = Date.now() - startedAt
128
+ console.log("")
129
+ console.log("UES bounded test summary")
130
+ console.log(`files: ${files.length}`)
131
+ console.log(`pass: ${passed}`)
132
+ console.log(`fail: ${failures.length}`)
133
+ console.log(`duration_ms: ${durationMs}`)
134
+
135
+ if (failures.length) {
136
+ console.error("")
137
+ console.error("Failing or leaking test files:")
138
+ for (const failure of failures) {
139
+ console.error(`- ${failure.file}: ${failure.reason}; duration=${failure.durationMs}ms`)
140
+ }
141
+ process.exitCode = 1
142
+ }
143
+ }
@@ -39,6 +39,8 @@ for (const required of [
39
39
  "pi/extensions/ues-child-runtime.ts",
40
40
  "docs/V14.2-TURBO-WEAK-MODEL-RUNTIME.md",
41
41
  "lib/process-supervisor.mjs",
42
+ "lib/executable-probe.mjs",
43
+ "lib/code-intelligence/lsp-pool.mjs",
42
44
  "lib/pi-rpc-pool.mjs",
43
45
  "lib/adaptive-context-budget.mjs",
44
46
  "lib/skill-compiler.mjs",
@@ -51,6 +53,8 @@ for (const required of [
51
53
  "lib/runtime-config.mjs",
52
54
  "scripts/eval-pi.mjs",
53
55
  "scripts/eval-report.mjs",
56
+ "scripts/benchmark-lsp-pool.mjs",
57
+ "scripts/run-test-suite.mjs",
54
58
  "evals/live/tasks.json",
55
59
  "global-config/AGENTS.md",
56
60
  "global-config/commands/run.md",