opencode-agent-skill 14.2.0-beta.1 → 15.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/README.md +51 -18
- package/docs/PI-COMPAT.md +167 -3
- package/docs/V15-MANAGED-RUNTIME.md +128 -0
- package/global-config/agents/architect.md +63 -1
- package/global-config/agents/executor.md +7 -0
- package/global-config/agents/plan-checker.md +8 -1
- package/global-config/agents/verifier.md +3 -3
- package/global-config/skills/database-engineering/references/workflow.md +15 -0
- package/global-config/skills/engineering-orchestrator/references/long-horizon.md +21 -11
- package/lib/activity-deadline.mjs +70 -0
- package/lib/adaptive-context-budget.mjs +25 -5
- package/lib/affected-tests.mjs +1 -1
- package/lib/capability-fabric.mjs +40 -0
- package/lib/code-intelligence/edit-anchor.mjs +102 -0
- package/lib/code-intelligence/index.mjs +95 -0
- package/lib/code-intelligence/lsp-provider.mjs +189 -0
- package/lib/completion-auditor.mjs +102 -0
- package/lib/document-ingestion.mjs +60 -0
- package/lib/evidence-store.mjs +92 -8
- package/lib/execution-contract.mjs +579 -0
- package/lib/fast-verification-gate.mjs +69 -0
- package/lib/leaf-runtime-optimizer.mjs +76 -0
- package/lib/mcp-health.mjs +144 -0
- package/lib/mcp-tool-policy.mjs +19 -0
- package/lib/memory-engine.mjs +28 -0
- package/lib/pi-child-invocation.mjs +65 -0
- package/lib/pi-rpc-pool.mjs +61 -9
- package/lib/plan-salvage.mjs +124 -0
- package/lib/planning-speed-policy.mjs +131 -0
- package/lib/prompt-cache.mjs +26 -12
- package/lib/repo-graph.mjs +1 -1
- package/lib/repo-inspect.mjs +1 -0
- package/lib/reversible-context.mjs +49 -0
- package/lib/runtime-artifacts.mjs +42 -0
- package/lib/runtime-events.mjs +33 -1
- package/lib/safety.mjs +1 -0
- package/lib/semantic-index.mjs +1 -1
- package/lib/service-manager.mjs +526 -0
- package/lib/session-display.mjs +49 -0
- package/lib/task-engine.mjs +6 -10
- package/lib/task-graph.mjs +87 -0
- package/lib/task-policy.mjs +210 -8
- package/lib/trajectory.mjs +111 -1
- package/lib/turbo-fast-path.mjs +44 -0
- package/lib/workspace-fingerprint.mjs +2 -11
- package/lib/workspace-root.mjs +49 -0
- package/lib/worktree-sandbox.mjs +234 -11
- package/package.json +9 -6
- package/pi/extensions/ues-child-runtime.ts +300 -2
- package/pi/extensions/ues.ts +1887 -160
- package/scripts/check-release-consistency.mjs +25 -2
- package/scripts/check-source-integrity.mjs +532 -3
- package/scripts/eval-pi.mjs +76 -36
- package/scripts/smoke-pi-extension.mjs +1 -1
- package/pi/prompts/ues-run.md +0 -17
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
function text(value) {
|
|
2
|
+
return String(value ?? "").trim()
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function reportSections(run) {
|
|
6
|
+
const sections = run?.report?.sections
|
|
7
|
+
return sections && typeof sections === "object" ? sections : {}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function passRun(run) {
|
|
11
|
+
return Boolean(run && Number(run.exitCode) === 0 && run.verdict === "PASS")
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function normalizeSection(value) {
|
|
15
|
+
return text(value)
|
|
16
|
+
.toLowerCase()
|
|
17
|
+
.replace(/[`*_#]/g, "")
|
|
18
|
+
.replace(/[.!:;]+$/g, "")
|
|
19
|
+
.replace(/\s+/g, " ")
|
|
20
|
+
.trim()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function benignEmptySection(value) {
|
|
24
|
+
const normalized = normalizeSection(value)
|
|
25
|
+
return !normalized || /^(?:none(?: observed| found| remaining)?|n\/a|na|nil|0|no failures?(?: observed| found| remaining)?|no unresolved gaps?(?: observed| found| remaining)?|no gaps?(?: observed| found| remaining)?|not applicable|không có|không có gì|không có lỗi|không phát hiện lỗi|không còn khoảng trống|không có khoảng trống)$/.test(normalized)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function benignFailureSection(value) {
|
|
29
|
+
const normalized = normalizeSection(value)
|
|
30
|
+
return benignEmptySection(normalized) ||
|
|
31
|
+
/^(?:không có|không phát hiện) .{0,120}(?:lỗi|thất bại)(?: nào)?$/.test(normalized)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function outOfScopeGapOnly(value) {
|
|
35
|
+
const normalized = normalizeSection(value)
|
|
36
|
+
if (benignEmptySection(normalized)) return true
|
|
37
|
+
return /(?:not requested|outside (?:the )?scope|out of scope|not required|không có yêu cầu|không được yêu cầu|ngoài phạm vi|không thuộc phạm vi)/.test(normalized)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function receiptPassed(row = {}) {
|
|
41
|
+
const receipt = row?.receipt || row
|
|
42
|
+
return Boolean(receipt?.passed === true && Number(receipt?.exitCode) === 0)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function auditCompletion(input = {}) {
|
|
46
|
+
const failures = []
|
|
47
|
+
const warnings = []
|
|
48
|
+
const verification = input.verification || null
|
|
49
|
+
const integration = input.integration || null
|
|
50
|
+
const visual = input.visual || null
|
|
51
|
+
const requireIntegration = input.requireIntegration === true
|
|
52
|
+
const requireVisual = input.requireVisual === true
|
|
53
|
+
const receipts = Array.isArray(input.behavioralReceipts) ? input.behavioralReceipts : []
|
|
54
|
+
|
|
55
|
+
if (!passRun(verification)) failures.push("primary-verification-not-pass")
|
|
56
|
+
if (requireIntegration && !passRun(integration)) failures.push("integration-verification-not-pass")
|
|
57
|
+
if (requireVisual && !passRun(visual)) failures.push("visual-verification-not-pass")
|
|
58
|
+
|
|
59
|
+
const sections = reportSections(verification)
|
|
60
|
+
for (const key of ["checks-run", "acceptance-criteria-proven", "completion-evidence"]) {
|
|
61
|
+
if (!text(sections[key])) failures.push(`missing-report-section:${key}`)
|
|
62
|
+
}
|
|
63
|
+
if (Object.hasOwn(sections, "failures") && !benignFailureSection(sections.failures)) failures.push("verification-reports-failures")
|
|
64
|
+
if (Object.hasOwn(sections, "unresolved-gaps") && !benignEmptySection(sections["unresolved-gaps"])) {
|
|
65
|
+
if (outOfScopeGapOnly(sections["unresolved-gaps"])) warnings.push("verification-reports-out-of-scope-gap")
|
|
66
|
+
else failures.push("verification-reports-unresolved-gaps")
|
|
67
|
+
}
|
|
68
|
+
if (Object.hasOwn(sections, "checks-not-run") && !benignEmptySection(sections["checks-not-run"])) warnings.push("verification-reports-checks-not-run")
|
|
69
|
+
|
|
70
|
+
const snapshot = input.workspaceSnapshot || null
|
|
71
|
+
if (snapshot) {
|
|
72
|
+
if (snapshot.cacheable === true && !text(snapshot.fingerprint)) failures.push("workspace-fingerprint-missing")
|
|
73
|
+
if (Array.isArray(snapshot.changedFiles) && snapshot.changedFiles.length === 0) warnings.push("workspace-has-no-detected-changes")
|
|
74
|
+
} else {
|
|
75
|
+
warnings.push("workspace-snapshot-unavailable")
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const passingReceipts = receipts.filter(receiptPassed)
|
|
79
|
+
if (input.requireBehavioralReceipt === true && passingReceipts.length === 0) failures.push("fresh-behavioral-receipt-missing")
|
|
80
|
+
else if (passingReceipts.length === 0) warnings.push("no-fresh-behavioral-receipt-attached")
|
|
81
|
+
|
|
82
|
+
const verifierOutput = text(verification?.output)
|
|
83
|
+
if (verification?.report?.valid === false) failures.push("verification-report-invalid")
|
|
84
|
+
if (verification?.report?.verdict && verification.report.verdict !== "PASS") failures.push("verification-report-verdict-mismatch")
|
|
85
|
+
if (/UES_VERDICT:\s*FAIL/i.test(verifierOutput)) failures.push("verifier-output-contains-fail-verdict")
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
schemaVersion: 1,
|
|
89
|
+
passed: failures.length === 0,
|
|
90
|
+
failures: [...new Set(failures)],
|
|
91
|
+
warnings: [...new Set(warnings)],
|
|
92
|
+
evidence: {
|
|
93
|
+
primary: passRun(verification),
|
|
94
|
+
integration: requireIntegration ? passRun(integration) : null,
|
|
95
|
+
visual: requireVisual ? passRun(visual) : null,
|
|
96
|
+
reportSections: Object.keys(sections).sort(),
|
|
97
|
+
passingReceiptCount: passingReceipts.length,
|
|
98
|
+
workspaceFingerprint: snapshot?.fingerprint || null,
|
|
99
|
+
changedFiles: Array.isArray(snapshot?.changedFiles) ? snapshot.changedFiles.slice(0, 200) : [],
|
|
100
|
+
},
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { lstat, readFile, realpath } from "node:fs/promises"
|
|
2
|
+
import { spawnSync } from "node:child_process"
|
|
3
|
+
import path from "node:path"
|
|
4
|
+
|
|
5
|
+
const BUILTIN_TEXT_EXTENSIONS = new Set([
|
|
6
|
+
".txt", ".md", ".markdown", ".json", ".jsonl", ".csv", ".tsv", ".xml", ".html", ".htm",
|
|
7
|
+
".yaml", ".yml", ".toml", ".ini", ".log", ".js", ".mjs", ".cjs", ".jsx", ".ts", ".tsx",
|
|
8
|
+
".py", ".java", ".kt", ".kts", ".cs", ".go", ".rs", ".rb", ".php", ".sql", ".css", ".scss",
|
|
9
|
+
])
|
|
10
|
+
const MARKITDOWN_EXTENSIONS = new Set([".pdf", ".docx", ".pptx", ".xlsx", ".xls", ".epub", ".zip"])
|
|
11
|
+
|
|
12
|
+
function inside(root, target) { return target === root || target.startsWith(root + path.sep) }
|
|
13
|
+
async function safeFile(root, relative) {
|
|
14
|
+
const base = await realpath(path.resolve(root)).catch(() => path.resolve(root))
|
|
15
|
+
const requested = path.resolve(base, String(relative || ""))
|
|
16
|
+
if (!inside(base, requested)) throw new Error("document path escapes workspace root")
|
|
17
|
+
const info = await lstat(requested)
|
|
18
|
+
if (!info.isFile()) throw new Error("document path is not a file")
|
|
19
|
+
const actual = await realpath(requested)
|
|
20
|
+
if (!inside(base, actual)) throw new Error("document symlink escapes workspace root")
|
|
21
|
+
return { base, file: actual, info }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function runMarkItDown(file, options = {}) {
|
|
25
|
+
const timeout = Math.max(5_000, Math.min(120_000, Number(options.timeoutMs || 30_000)))
|
|
26
|
+
const maxBuffer = Math.max(256 * 1024, Math.min(16 * 1024 * 1024, Number(options.maxBuffer || 4 * 1024 * 1024)))
|
|
27
|
+
const attempts = process.platform === "win32"
|
|
28
|
+
? [["markitdown.exe", [file]], ["markitdown", [file]], ["py", ["-m", "markitdown", file]], ["python", ["-m", "markitdown", file]]]
|
|
29
|
+
: [["markitdown", [file]], ["python3", ["-m", "markitdown", file]], ["python", ["-m", "markitdown", file]]]
|
|
30
|
+
for (const [command, args] of attempts) {
|
|
31
|
+
const result = spawnSync(command, args, { encoding: "utf8", timeout, maxBuffer, windowsHide: true })
|
|
32
|
+
if (result.status === 0 && String(result.stdout || "").trim()) return { provider: command.includes("python") || command === "py" ? "markitdown-python" : "markitdown-cli", markdown: String(result.stdout) }
|
|
33
|
+
if (result.error?.code !== "ENOENT" && result.status != null) return { provider: "markitdown-unavailable", error: String(result.stderr || result.error?.message || `exit ${result.status}`) }
|
|
34
|
+
}
|
|
35
|
+
return { provider: "markitdown-unavailable", error: "MarkItDown command/module was not found" }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function documentIngestionSupport(file = "") {
|
|
39
|
+
const ext = path.extname(String(file)).toLowerCase()
|
|
40
|
+
return { schemaVersion: 1, extension: ext, builtin: BUILTIN_TEXT_EXTENSIONS.has(ext), markitdown: MARKITDOWN_EXTENSIONS.has(ext), supported: BUILTIN_TEXT_EXTENSIONS.has(ext) || MARKITDOWN_EXTENSIONS.has(ext) }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function ingestDocument(root, relative, options = {}) {
|
|
44
|
+
const target = await safeFile(root, relative)
|
|
45
|
+
const support = documentIngestionSupport(target.file)
|
|
46
|
+
const maxBytes = Math.max(16 * 1024, Math.min(32 * 1024 * 1024, Number(options.maxBytes || 4 * 1024 * 1024)))
|
|
47
|
+
if (target.info.size > maxBytes) throw new Error(`document exceeds ingestion limit (${target.info.size} > ${maxBytes} bytes)`)
|
|
48
|
+
if (support.builtin) {
|
|
49
|
+
const content = await readFile(target.file, "utf8")
|
|
50
|
+
return { schemaVersion: 1, provider: "builtin-text", file: path.relative(target.base, target.file).replaceAll("\\", "/"), bytes: target.info.size, markdown: content, optionalDependency: false }
|
|
51
|
+
}
|
|
52
|
+
if (support.markitdown) {
|
|
53
|
+
const converted = runMarkItDown(target.file, options)
|
|
54
|
+
if (converted.markdown) return { schemaVersion: 1, provider: converted.provider, file: path.relative(target.base, target.file).replaceAll("\\", "/"), bytes: target.info.size, markdown: converted.markdown, optionalDependency: true }
|
|
55
|
+
const error = new Error(`${converted.error}. Install Microsoft MarkItDown only when Office/PDF ingestion is needed.`)
|
|
56
|
+
error.code = "UES_MARKITDOWN_UNAVAILABLE"
|
|
57
|
+
throw error
|
|
58
|
+
}
|
|
59
|
+
throw new Error(`unsupported document extension: ${support.extension || "(none)"}`)
|
|
60
|
+
}
|
package/lib/evidence-store.mjs
CHANGED
|
@@ -5,6 +5,41 @@ import path from "node:path"
|
|
|
5
5
|
|
|
6
6
|
const STORE_VERSION = 1
|
|
7
7
|
const REF_PREFIX = "evidence:sha256:"
|
|
8
|
+
const DEFAULT_MAX_STORE_BYTES = 192 * 1024 * 1024
|
|
9
|
+
const DEFAULT_MAX_STORE_ENTRIES = 1200
|
|
10
|
+
const DEFAULT_MAX_STORE_AGE_DAYS = 14
|
|
11
|
+
const AUTO_GC_EVERY_WRITES = 8
|
|
12
|
+
const AUTO_GC_LARGE_ITEM_BYTES = 16 * 1024 * 1024
|
|
13
|
+
const PUT_COUNTS = new Map()
|
|
14
|
+
|
|
15
|
+
function boundedNumber(value, fallback, min, max) {
|
|
16
|
+
const parsed = Number(value)
|
|
17
|
+
if (!Number.isFinite(parsed)) return fallback
|
|
18
|
+
return Math.max(min, Math.min(max, Math.trunc(parsed)))
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function defaultStoreLimits() {
|
|
22
|
+
return {
|
|
23
|
+
maxBytes: boundedNumber(
|
|
24
|
+
process.env.UES_EVIDENCE_MAX_BYTES,
|
|
25
|
+
DEFAULT_MAX_STORE_BYTES,
|
|
26
|
+
16 * 1024 * 1024,
|
|
27
|
+
2 * 1024 * 1024 * 1024,
|
|
28
|
+
),
|
|
29
|
+
maxEntries: boundedNumber(
|
|
30
|
+
process.env.UES_EVIDENCE_MAX_ENTRIES,
|
|
31
|
+
DEFAULT_MAX_STORE_ENTRIES,
|
|
32
|
+
100,
|
|
33
|
+
20_000,
|
|
34
|
+
),
|
|
35
|
+
maxAgeDays: boundedNumber(
|
|
36
|
+
process.env.UES_EVIDENCE_MAX_AGE_DAYS,
|
|
37
|
+
DEFAULT_MAX_STORE_AGE_DAYS,
|
|
38
|
+
1,
|
|
39
|
+
365,
|
|
40
|
+
),
|
|
41
|
+
}
|
|
42
|
+
}
|
|
8
43
|
|
|
9
44
|
function stableValue(value) {
|
|
10
45
|
if (Array.isArray(value)) return value.map(stableValue)
|
|
@@ -21,6 +56,24 @@ function toBytes(value, options = {}) {
|
|
|
21
56
|
return { bytes: Buffer.from(text, "utf8"), encoding: "utf8", mediaType: options.mediaType || "application/json" }
|
|
22
57
|
}
|
|
23
58
|
|
|
59
|
+
async function protectedEvidenceHashes(root) {
|
|
60
|
+
const file = path.join(path.resolve(root), ".ues-memory", "MEMORY.json")
|
|
61
|
+
const parsed = await readFile(file, "utf8")
|
|
62
|
+
.then((raw) => JSON.parse(raw))
|
|
63
|
+
.catch(() => null)
|
|
64
|
+
const protectedHashes = new Set()
|
|
65
|
+
const now = Date.now()
|
|
66
|
+
for (const memory of parsed?.memories || []) {
|
|
67
|
+
if (memory?.status !== "verified" || memory?.supersededBy) continue
|
|
68
|
+
const expiresAt = Date.parse(String(memory?.expiresAt || ""))
|
|
69
|
+
if (expiresAt && expiresAt <= now) continue
|
|
70
|
+
for (const ref of memory?.evidenceRefs || []) {
|
|
71
|
+
try { protectedHashes.add(normalizeHash(ref)) } catch {}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return protectedHashes
|
|
75
|
+
}
|
|
76
|
+
|
|
24
77
|
function normalizeHash(ref) {
|
|
25
78
|
const value = String(ref || "").trim()
|
|
26
79
|
const hash = value.startsWith(REF_PREFIX) ? value.slice(REF_PREFIX.length) : value.replace(/^sha256:/, "")
|
|
@@ -79,6 +132,13 @@ export async function putEvidence(root, value, options = {}) {
|
|
|
79
132
|
preview,
|
|
80
133
|
}
|
|
81
134
|
await writeFile(target.meta, JSON.stringify(metadata, null, 2) + "\n", "utf8")
|
|
135
|
+
|
|
136
|
+
const writes = (PUT_COUNTS.get(root) || 0) + 1
|
|
137
|
+
PUT_COUNTS.set(root, writes)
|
|
138
|
+
if (writes % AUTO_GC_EVERY_WRITES === 0 || encoded.bytes.length >= AUTO_GC_LARGE_ITEM_BYTES) {
|
|
139
|
+
await gcEvidenceStore(root, defaultStoreLimits()).catch(() => null)
|
|
140
|
+
}
|
|
141
|
+
|
|
82
142
|
return metadata
|
|
83
143
|
}
|
|
84
144
|
|
|
@@ -216,25 +276,44 @@ export async function evidenceStoreStatus(root = process.cwd()) {
|
|
|
216
276
|
}
|
|
217
277
|
|
|
218
278
|
export async function gcEvidenceStore(root = process.cwd(), options = {}) {
|
|
279
|
+
root = path.resolve(root)
|
|
219
280
|
const files = await metadataFiles(root)
|
|
220
|
-
const
|
|
221
|
-
const
|
|
281
|
+
const defaults = defaultStoreLimits()
|
|
282
|
+
const maxEntries = Math.max(10, Number(options.maxEntries ?? defaults.maxEntries))
|
|
283
|
+
const maxBytes = Math.max(1024 * 1024, Number(options.maxBytes ?? defaults.maxBytes))
|
|
284
|
+
const maxAgeMs = Math.max(0, Number(options.maxAgeDays ?? defaults.maxAgeDays)) * 86_400_000
|
|
222
285
|
const now = Date.now()
|
|
286
|
+
const protectedHashes = options.protectMemoryRefs === false
|
|
287
|
+
? new Set()
|
|
288
|
+
: await protectedEvidenceHashes(root)
|
|
223
289
|
const rows = []
|
|
224
290
|
for (const metaFile of files) {
|
|
225
291
|
const meta = JSON.parse(await readFile(metaFile, "utf8").catch(() => "{}"))
|
|
226
292
|
const time = Date.parse(meta.lastSeenAt || meta.createdAt || 0) || 0
|
|
227
|
-
rows.push({ metaFile, meta, time })
|
|
293
|
+
rows.push({ metaFile, meta, time, bytes: Math.max(0, Number(meta.bytes || 0)) })
|
|
228
294
|
}
|
|
229
295
|
rows.sort((a, b) => b.time - a.time)
|
|
230
296
|
|
|
231
297
|
const removed = []
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
298
|
+
let retainedEntries = 0
|
|
299
|
+
let retainedBytes = 0
|
|
300
|
+
let protectedEntries = 0
|
|
301
|
+
let protectedBytes = 0
|
|
302
|
+
for (const row of rows) {
|
|
303
|
+
const hash = normalizeHash(row.meta.sha256 || path.basename(row.metaFile, ".json"))
|
|
304
|
+
const protectedByMemory = protectedHashes.has(hash)
|
|
305
|
+
const tooMany = retainedEntries >= maxEntries
|
|
235
306
|
const tooOld = maxAgeMs > 0 && row.time > 0 && now - row.time > maxAgeMs
|
|
236
|
-
|
|
237
|
-
|
|
307
|
+
const tooLarge = retainedBytes + row.bytes > maxBytes
|
|
308
|
+
if (protectedByMemory || (!tooMany && !tooOld && !tooLarge)) {
|
|
309
|
+
retainedEntries += 1
|
|
310
|
+
retainedBytes += row.bytes
|
|
311
|
+
if (protectedByMemory) {
|
|
312
|
+
protectedEntries += 1
|
|
313
|
+
protectedBytes += row.bytes
|
|
314
|
+
}
|
|
315
|
+
continue
|
|
316
|
+
}
|
|
238
317
|
const target = evidencePaths(root, hash)
|
|
239
318
|
await rm(target.meta, { force: true })
|
|
240
319
|
await rm(target.data, { force: true })
|
|
@@ -244,6 +323,11 @@ export async function gcEvidenceStore(root = process.cwd(), options = {}) {
|
|
|
244
323
|
return {
|
|
245
324
|
removed,
|
|
246
325
|
removedCount: removed.length,
|
|
326
|
+
retainedEntries,
|
|
327
|
+
retainedBytes,
|
|
328
|
+
protectedEntries,
|
|
329
|
+
protectedBytes,
|
|
330
|
+
limits: { maxEntries, maxBytes, maxAgeMs },
|
|
247
331
|
status: await evidenceStoreStatus(root),
|
|
248
332
|
}
|
|
249
333
|
}
|