opencode-agent-skill 13.0.0-beta.1 → 14.2.0-beta.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 (95) hide show
  1. package/README.md +1557 -606
  2. package/bin/ocskill.mjs +172 -24
  3. package/docs/OPENCODE-COMPAT.md +34 -95
  4. package/docs/PI-COMPAT.md +188 -0
  5. package/docs/V14-CONTEXT-MEMORY-FABRIC.md +70 -0
  6. package/docs/V14.1-QUALITY-PERFORMANCE-FABRIC.md +114 -0
  7. package/docs/V14.2-TURBO-WEAK-MODEL-RUNTIME.md +448 -0
  8. package/evals/v14/tasks.json +46 -0
  9. package/global-config/agents/executor.md +7 -0
  10. package/global-config/agents/visual-verifier.md +22 -3
  11. package/global-config/commands/run.md +27 -20
  12. package/global-config/plugins/ues-router/command-runtime.js +54 -0
  13. package/global-config/plugins/ues-router/index.js +30 -24
  14. package/global-config/plugins/ues-router/policy-runtime.js +7 -0
  15. package/global-config/plugins/ues-router/router.js +12 -2
  16. package/global-config/skills/ecommerce-engineering/SKILL.md +1 -1
  17. package/global-config/skills/file-upload-engineering/SKILL.md +1 -1
  18. package/global-config/skills/git-safety/SKILL.md +1 -1
  19. package/global-config/skills/nestjs-engineering/SKILL.md +1 -1
  20. package/global-config/skills/performance-engineering/SKILL.md +1 -1
  21. package/global-config/skills/react-native-engineering/SKILL.md +1 -1
  22. package/global-config/skills/rest-api-design/SKILL.md +1 -1
  23. package/global-config/skills/ui-ux-engineering/SKILL.md +1 -1
  24. package/lib/adaptive-context-budget.mjs +97 -0
  25. package/lib/affected-tests.mjs +260 -0
  26. package/lib/benchmark-confidence.mjs +41 -2
  27. package/lib/browser-mcp-routing.mjs +166 -0
  28. package/lib/capability-fabric.mjs +336 -0
  29. package/lib/capability-registry.mjs +9 -0
  30. package/lib/context-engine-v11.mjs +65 -1
  31. package/lib/context-graph-rank.mjs +118 -0
  32. package/lib/context-manifest.mjs +97 -18
  33. package/lib/control-center.mjs +19 -1
  34. package/lib/dynamic-workflow.mjs +3 -1
  35. package/lib/evidence-store.mjs +82 -1
  36. package/lib/hierarchical-context.mjs +215 -0
  37. package/lib/memory-engine.mjs +465 -0
  38. package/lib/model-performance.mjs +33 -8
  39. package/lib/model-policy.mjs +3 -3
  40. package/lib/orchestrator-policy.mjs +5 -209
  41. package/lib/performance-fabric.mjs +229 -0
  42. package/lib/pi-rpc-pool.mjs +433 -0
  43. package/lib/process-hang-detector.mjs +83 -0
  44. package/lib/process-supervisor.mjs +193 -0
  45. package/lib/prompt-cache.mjs +2 -0
  46. package/lib/repo-graph.mjs +53 -2
  47. package/lib/runtime-config.mjs +31 -0
  48. package/lib/safety.mjs +132 -0
  49. package/lib/semantic-index.mjs +52 -3
  50. package/lib/skill-compiler.mjs +128 -0
  51. package/lib/skill-quality.mjs +48 -2
  52. package/lib/task-engine.mjs +66 -5
  53. package/lib/task-policy.mjs +235 -0
  54. package/lib/verification-broker.mjs +284 -0
  55. package/lib/verification-command.mjs +111 -0
  56. package/lib/windows-shim.mjs +35 -0
  57. package/lib/workspace-fingerprint.mjs +198 -0
  58. package/package.json +52 -42
  59. package/pi/extensions/ues-child-runtime.ts +238 -0
  60. package/pi/extensions/ues.ts +3200 -0
  61. package/pi/prompts/ues-audit.md +9 -0
  62. package/pi/prompts/ues-critique.md +9 -0
  63. package/pi/prompts/ues-debug.md +9 -0
  64. package/pi/prompts/ues-feature.md +9 -0
  65. package/pi/prompts/ues-fix.md +9 -0
  66. package/pi/prompts/ues-plan.md +9 -0
  67. package/pi/prompts/ues-research.md +9 -0
  68. package/pi/prompts/ues-resume.md +9 -0
  69. package/pi/prompts/ues-review.md +7 -0
  70. package/pi/prompts/ues-run.md +17 -0
  71. package/pi/prompts/ues-verify.md +9 -0
  72. package/scripts/check-release-consistency.mjs +119 -185
  73. package/scripts/check-runtime-exports.mjs +66 -0
  74. package/scripts/check-source-integrity.mjs +184 -0
  75. package/scripts/eval-pi.mjs +492 -0
  76. package/scripts/install.mjs +16 -0
  77. package/scripts/smoke-package-closure.mjs +110 -0
  78. package/scripts/smoke-packed-install.mjs +24 -11
  79. package/scripts/smoke-pi-extension.mjs +144 -0
  80. package/scripts/uninstall.mjs +44 -0
  81. package/CHANGELOG.md +0 -405
  82. package/docs/DETERMINISTIC-TOOLS.md +0 -105
  83. package/docs/ENGINEERING-DESIGN.md +0 -194
  84. package/docs/EVALS.md +0 -158
  85. package/docs/GITHUB-RULESET.md +0 -50
  86. package/docs/NPM-PUBLISH.md +0 -116
  87. package/docs/RESEARCH-SOURCES.md +0 -37
  88. package/docs/TRACE-SCHEMA.md +0 -122
  89. package/docs/V11-PERCEPTION-ADAPTIVE-EXECUTION.md +0 -75
  90. package/docs/V11-PERCEPTION-ADAPTIVE.md +0 -220
  91. package/docs/V12-WEAK-MODEL-INTELLIGENCE.md +0 -27
  92. package/docs/V13-PARALLEL-WEAK-MODEL-RUNTIME.md +0 -75
  93. package/docs/V7-INTELLIGENCE-RUNTIME.md +0 -166
  94. package/docs/V8-INTELLIGENCE-RELIABILITY.md +0 -206
  95. package/docs/V9-SPEED-INTELLIGENCE.md +0 -102
@@ -0,0 +1,9 @@
1
+ ---
2
+ description: Audit a codebase or change for correctness, security, integration and verification gaps.
3
+ ---
4
+
5
+ Audit this scope: $@
6
+
7
+ Use targeted repository evidence before conclusions. Prefer a fresh `ues-reviewer`, and use domain skills for auth, payment, database, API, browser or deployment boundaries when applicable. Distinguish confirmed defects from risks that require more evidence.
8
+
9
+ Report findings by severity with file/location, impact, evidence, and a concrete verification/fix direction. Do not make edits unless the user asks for them.
@@ -0,0 +1,9 @@
1
+ ---
2
+ description: Challenge a proposed implementation or plan for hidden assumptions, failure modes and missing evidence.
3
+ ---
4
+
5
+ Critique this proposal or implementation: $@
6
+
7
+ Use `ues_dispatch` with `ues-critic` for independent fresh context when useful. Look for incorrect assumptions, missing dependencies, unsafe ordering, inadequate rollback, weak acceptance criteria, test gaps, and unnecessary complexity. Ground each objection in concrete repository or requirement evidence.
8
+
9
+ Do not turn critique into an implementation unless asked.
@@ -0,0 +1,9 @@
1
+ ---
2
+ description: Diagnose a failure from reproducible evidence before applying a bounded fix.
3
+ ---
4
+
5
+ Debug this problem: $@
6
+
7
+ Reproduce or capture the exact failure first. Use `ues_cli` for deterministic repo/test evidence and `ues_dispatch` with `ues-debugger` when fresh context helps. Trace where the state/value first becomes wrong, test one causal hypothesis at a time, and avoid speculative patch stacking.
8
+
9
+ If a code change is requested, make the smallest supported fix and verify the original failure plus affected checks. Preserve unrelated user changes.
@@ -0,0 +1,9 @@
1
+ ---
2
+ description: Implement a feature through adaptive UES planning, bounded edits and evidence-backed verification.
3
+ ---
4
+
5
+ Implement this feature: $@
6
+
7
+ Use the same adaptive admission rules as `/ues-run`. Determine scope with `ues_cli task-policy`; avoid durable state for small work and use `.ues-work/<slug>/` for long/high-risk work. For complex changes, use a fresh `ues-architect` or `ues-plan-checker` before implementation, then `ues-executor` and `ues-verifier`.
8
+
9
+ Keep changes file-aware and dependency-aware, preserve existing contracts unless the requirement changes them, and finish with fresh tests plus final diff/status evidence.
@@ -0,0 +1,9 @@
1
+ ---
2
+ description: Fix a verified bug with UES diagnosis, bounded implementation and fresh verification.
3
+ ---
4
+
5
+ Fix this problem: $@
6
+
7
+ First establish the failure and root-cause evidence. For non-trivial bugs, use `ues_dispatch` as a chain: `ues-debugger` to diagnose, `ues-executor` to implement the smallest supported fix, then `ues-verifier` to independently verify. Pass prior output with `{previous}` where useful.
8
+
9
+ Do not stack speculative fixes. Preserve unrelated changes. Run the exact failing check again and then affected checks. Do not push, publish, deploy or perform destructive operations without explicit approval.
@@ -0,0 +1,9 @@
1
+ ---
2
+ description: Produce an implementation-ready UES plan on Pi without editing code.
3
+ ---
4
+
5
+ Plan this engineering task without editing files: $@
6
+
7
+ Inspect repository instructions, relevant entry points, interfaces, callers, tests, nearest working analogues, and constraints. Use `ues_cli` for deterministic repository/evidence commands when useful. For a complex plan, use `ues_dispatch` with `ues-architect` and optionally `ues-plan-checker`.
8
+
9
+ Define observable acceptance criteria, blast radius, ordered implementation steps, dependencies, file/resource scopes, rollback or compatibility concerns, and verification for each risky boundary. Call out unresolved decisions rather than inventing them.
@@ -0,0 +1,9 @@
1
+ ---
2
+ description: Research an engineering question with source verification and repository-aware synthesis.
3
+ ---
4
+
5
+ Research this engineering question: $@
6
+
7
+ Use repository evidence for project-specific claims and authoritative current sources when external facts may have changed. A fresh `ues-researcher` may be used through `ues_dispatch` to keep exploration out of the main context.
8
+
9
+ Separate verified facts, assumptions, and unresolved questions. Return only findings relevant to the requested decision or implementation.
@@ -0,0 +1,9 @@
1
+ ---
2
+ description: Resume an interrupted durable UES work item on Pi from filesystem and Git evidence.
3
+ ---
4
+
5
+ Resume this UES work item: $@
6
+
7
+ Treat only `.ues-work/<slug>/` as canonical durable UES state. Read SPEC, PLAN, STATE, EVIDENCE, task reports and current Git status. Use `ues_cli` with `["work","resume","<slug>","."]` (and `work recover` when needed) before deciding the next dependency-safe action.
8
+
9
+ Trust durable state and current repository evidence over conversational recollection. Do not repeat completed tasks unless fresh evidence invalidates them. Use `ues_dispatch` for fresh executor/verifier context. Parallel writers require distinct isolated cwd/worktrees. After all tasks complete, use a fresh `ues-integration-verifier`, record the integration result through `ues_cli`, and finalize only after PASS with an unchanged workspace fingerprint.
@@ -0,0 +1,7 @@
1
+ ---
2
+ description: Review code changes for correctness, regressions, safety and missing verification using a fresh UES reviewer.
3
+ ---
4
+
5
+ Review this change or repository scope: $@
6
+
7
+ Inspect the current diff and affected call paths. Use `ues_dispatch` with `ues-reviewer` for fresh context when useful. Prioritize concrete correctness bugs, regressions, security boundaries, data loss risks, race conditions, broken contracts, and missing tests. Ground findings in repository evidence and include exact files/locations. Do not invent issues to fill a checklist.
@@ -0,0 +1,17 @@
1
+ ---
2
+ description: Execute engineering work through the deterministic UES runtime controller on Pi, with adaptive context, model routing, retries, and evidence-gated verification.
3
+ ---
4
+
5
+ Run this task with UES on Pi: $@
6
+
7
+ Preserve the user's requested outcome and approval boundaries.
8
+
9
+ 1. If the request is directly answerable and needs no repository evidence, edits, or machine-checkable verification, answer directly.
10
+ 2. Otherwise prefer the `ues_execute` tool for end-to-end engineering work. Pass a concise but complete task and the current repository cwd. The controller owns task policy, bounded context construction, model-tier routing, optional diagnosis/plan gating, implementation, retries, independent verification, integration verification, and performance telemetry.
11
+ 3. Do not manually reproduce the controller workflow unless `ues_execute` is unavailable or the user explicitly asks for plan-only/review-only/research-only work.
12
+ 4. Use `ues_cli` for deterministic inspection, durable `.ues-work/` state, task graphs, receipts, evidence, worktrees, browser/visual helpers, and explicit policy/config operations.
13
+ 5. Use `ues_dispatch` when you intentionally need one specialist, a custom chain, or bounded parallel read-only work. Routed dispatch automatically applies model policy and adaptive context.
14
+ 6. Parallel read-only agents may share the repository. Parallel writer agents must use explicit distinct isolated cwd/worktrees; otherwise run writers serially. Never bypass this guard.
15
+ 7. Preserve unrelated user changes. Do not force-clean a repository.
16
+ 8. Do not merge, push, publish, deploy, rewrite history, or perform destructive operations without explicit user approval.
17
+ 9. Final completion claims must come from a verified controller PASS or equivalent fresh command/test evidence plus the final diff/status.
@@ -0,0 +1,9 @@
1
+ ---
2
+ description: Verify requested behavior with fresh evidence and no unsupported completion claims.
3
+ ---
4
+
5
+ Verify this engineering work: $@
6
+
7
+ Start from the acceptance criteria and the actual current diff/status. Prefer the narrowest project-native checks that prove the claim, then expand according to blast radius. Use `ues_cli` for deterministic UES evidence/receipt commands and `ues_dispatch` with `ues-verifier` or `ues-integration-verifier` for independent fresh context.
8
+
9
+ Do not edit merely to make verification pass unless the user asked for a fix. Report failed checks, skipped checks, unresolved gaps, and exactly what the evidence proves.
@@ -8,236 +8,170 @@ const DEFAULT_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)),
8
8
 
9
9
  function readJson(root, relative) {
10
10
  const file = path.join(root, relative)
11
- if (!existsSync(file)) {
12
- return { ok: false, error: `${relative}: file not found`, value: null }
13
- }
11
+ if (!existsSync(file)) return { ok: false, error: `${relative}: file not found`, value: null }
14
12
  try {
15
13
  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 }
14
+ } catch (error) {
15
+ return {
16
+ ok: false,
17
+ error: `${relative}: invalid JSON (${error instanceof Error ? error.message : String(error)})`,
18
+ value: null,
19
+ }
18
20
  }
19
21
  }
20
22
 
21
23
  function readText(root, relative) {
22
24
  const file = path.join(root, relative)
23
- if (!existsSync(file)) {
24
- return { ok: false, error: `${relative}: file not found`, value: null }
25
- }
25
+ if (!existsSync(file)) return { ok: false, error: `${relative}: file not found`, value: null }
26
26
  return { ok: true, error: null, value: readFileSync(file, "utf8") }
27
27
  }
28
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 }
29
+ function countDir(root, relative, predicate) {
30
+ const dir = path.join(root, relative)
31
+ if (!existsSync(dir)) return { ok: false, error: `${relative}: directory not found`, value: 0 }
32
+ const entries = readdirSync(dir, { withFileTypes: true })
33
+ return {
34
+ ok: true,
35
+ error: null,
36
+ value: predicate ? entries.filter(predicate).length : entries.length,
37
+ }
35
38
  }
36
39
 
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 }
40
+ function countSkills(root) {
41
+ return countDir(root, path.join("global-config", "skills"), (entry) =>
42
+ entry.isDirectory() && existsSync(path.join(root, "global-config", "skills", entry.name, "SKILL.md"))
43
+ )
44
+ }
45
+
46
+ function requireText(errors, result, relative) {
47
+ if (result.ok) return result.value
48
+ errors.push(result.error || `${relative}: unavailable`)
49
+ return ""
45
50
  }
46
51
 
47
- export function checkReleaseConsistency(root) {
48
- root = root || DEFAULT_ROOT
52
+ export function checkReleaseConsistency(root = DEFAULT_ROOT) {
49
53
  const errors = []
50
54
  const warnings = []
51
55
 
52
- function rJson(relative) {
53
- return readJson(root, relative)
54
- }
55
- function rText(relative) {
56
- return readText(root, relative)
56
+ const pkgResult = readJson(root, "package.json")
57
+ const lockResult = readJson(root, "package-lock.json")
58
+ const pkg = pkgResult.ok ? pkgResult.value : null
59
+ const lock = lockResult.ok ? lockResult.value : null
60
+ if (!pkgResult.ok) errors.push(pkgResult.error)
61
+ if (!lockResult.ok) errors.push(lockResult.error)
62
+
63
+ const version = pkg?.version || "unknown"
64
+ if (pkg && lock && pkg.version !== lock.version) {
65
+ errors.push(`package.json version (${pkg.version}) != package-lock.json version (${lock.version})`)
57
66
  }
58
- function rCount(dirPath, filter) {
59
- return countDir(root, dirPath, filter)
67
+ if (pkg && lock?.packages?.[""]?.version && pkg.version !== lock.packages[""].version) {
68
+ errors.push(`package-lock root package version (${lock.packages[""].version}) != package.json version (${pkg.version})`)
60
69
  }
61
70
 
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})`)
71
+ const expectedBins = { ues: "bin/ocskill.mjs", ocskill: "bin/ocskill.mjs" }
72
+ if (pkg) {
73
+ for (const [name, target] of Object.entries(expectedBins)) {
74
+ if (pkg.bin?.[name] !== target) errors.push(`package.json: bin.${name} must be ${target}`)
75
+ if (lock?.packages?.[""]?.bin?.[name] !== target) {
76
+ errors.push(`package-lock.json: root bin.${name} must be ${target}`)
77
+ }
70
78
  }
71
- } else {
72
- if (!pkg.ok) errors.push(pkg.error)
73
- if (!lock.ok) errors.push(lock.error)
74
79
  }
75
80
 
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)
81
+ const skillResult = countSkills(root)
82
+ const commandResult = countDir(root, path.join("global-config", "commands"), (entry) => entry.isFile() && entry.name.endsWith(".md"))
83
+ const agentResult = countDir(root, path.join("global-config", "agents"), (entry) => entry.isFile() && entry.name.endsWith(".md"))
84
+ const promptResult = countDir(root, path.join("pi", "prompts"), (entry) => entry.isFile() && entry.name.endsWith(".md"))
85
+ for (const result of [skillResult, commandResult, agentResult, promptResult]) {
86
+ if (!result.ok) errors.push(result.error)
87
+ }
88
+ const skillCount = skillResult.value || 0
89
+ const commandCount = commandResult.value || 0
90
+ const subagentCount = agentResult.value || 0
91
+ const promptCount = promptResult.value || 0
86
92
 
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
93
+ const routing = readJson(root, path.join("evals", "routing.json"))
94
+ const routerTriggers = readJson(root, path.join("evals", "router-triggers.json"))
92
95
  if (!routing.ok) errors.push(routing.error)
93
96
  if (!routerTriggers.ok) errors.push(routerTriggers.error)
97
+ const staticScenarioCount = routing.ok && Array.isArray(routing.value.scenarios) ? routing.value.scenarios.length : 0
98
+ const routerCaseCount = routerTriggers.ok && Array.isArray(routerTriggers.value.cases) ? routerTriggers.value.cases.length : 0
94
99
 
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 + ")")
100
+ const readme = requireText(errors, readText(root, "README.md"), "README.md")
101
+ if (readme) {
102
+ const versionMatches = [
103
+ readme.match(/Phiên bản package hiện tại:\*\*\s*<code>([^<]+)<\/code>/i),
104
+ readme.match(/Phiên bản hiện tại:\s*\n```text\n(\S+)/i),
105
+ ].filter(Boolean)
106
+ const readmeVersion = versionMatches[0]?.[1] || null
107
+ if (!readmeVersion) errors.push("README.md: could not find current package version")
108
+ else if (readmeVersion !== version) errors.push(`README.md: current version says ${readmeVersion}, expected ${version}`)
109
+ for (const marker of ["**Pi Agent**", "ues_execute", "ues_dispatch", "ues_cli", "V14.2 Turbo Weak-Model Runtime"]) {
110
+ if (!readme.includes(marker)) errors.push(`README.md: missing Pi runtime marker ${marker}`)
109
111
  }
110
- } else {
111
- errors.push(readme.error)
112
112
  }
113
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`)
114
+ const piCompat = requireText(errors, readText(root, path.join("docs", "PI-COMPAT.md")), "docs/PI-COMPAT.md")
115
+ if (piCompat) {
116
+ for (const marker of ["# Pi Agent runtime", "ues_execute", "ues_dispatch", "ues_cli", "manifest is Pi-only", "V14.2 Turbo Weak-Model Runtime"]) {
117
+ if (!piCompat.includes(marker)) errors.push(`docs/PI-COMPAT.md: missing current Pi contract marker ${marker}`)
130
118
  }
131
119
  }
132
120
 
133
- // 4b. V13 prerelease contract must stay synchronized with compatibility docs.
134
- if (expectedVersion.startsWith("13.")) {
135
- const v13 = rText("docs/V13-PARALLEL-WEAK-MODEL-RUNTIME.md")
136
- if (!v13.ok) {
137
- errors.push(v13.error)
138
- } else {
139
- if (!v13.value.includes("Status: beta prerelease (`" + expectedVersion + "`).")) {
140
- errors.push("docs/V13-PARALLEL-WEAK-MODEL-RUNTIME.md: prerelease version/status drift")
141
- }
142
- for (const required of ["ues.dispatch_parallel", "same configured model", "OpenCode"]) {
143
- if (!v13.value.includes(required)) {
144
- errors.push("docs/V13-PARALLEL-WEAK-MODEL-RUNTIME.md: missing V13 contract marker " + required)
145
- }
146
- }
147
- }
148
-
149
- const compat = rText("docs/OPENCODE-COMPAT.md")
150
- if (!compat.ok) {
151
- errors.push(compat.error)
152
- } else {
153
- if (!compat.value.includes("V13 ships one npm package")) {
154
- errors.push("docs/OPENCODE-COMPAT.md: current compatibility header is stale for V13")
155
- }
156
- if (!compat.value.includes("ues.dispatch_parallel")) {
157
- errors.push("docs/OPENCODE-COMPAT.md: missing V13 parallel capability boundary")
158
- }
121
+ const openCodeCompat = requireText(errors, readText(root, path.join("docs", "OPENCODE-COMPAT.md")), "docs/OPENCODE-COMPAT.md")
122
+ if (openCodeCompat) {
123
+ for (const marker of ["Deprecated compatibility surface", "supported runtime in this repository is **Pi Agent**", "canonical runtime lives under `pi/` and `lib/`", "compatibility shim"]) {
124
+ if (!openCodeCompat.includes(marker)) errors.push(`docs/OPENCODE-COMPAT.md: missing legacy-boundary marker ${marker}`)
159
125
  }
160
126
  }
161
127
 
162
- // 5. Verify docs reflect actual counts (skip historical sections)
163
- const docsToCheck = ["README.md", "docs/ENGINEERING-DESIGN.md", "docs/OPENCODE-COMPAT.md"]
164
- for (const doc of docsToCheck) {
165
- const content = rText(doc)
166
- if (!content.ok) {
167
- errors.push(content.error)
168
- continue
169
- }
170
- const sections = content.value.split(/\n(?=#{1,6}\s)/)
171
- for (const section of sections) {
172
- const isHistorical = /^\s*#{1,6}\s+.*(V\d+\.|UES\s+\d+\.|historical|Historical)/im.test(section)
173
- if (isHistorical) continue
174
- if (section.includes("39 skills") || section.includes("39 namespaced skills")) {
175
- errors.push(`${doc}: current section still references 39 skills (actual: ${skillCount})`)
176
- }
177
- if (section.includes("10 namespaced subagents") || section.includes("10 subagents")) {
178
- errors.push(`${doc}: current section still references 10 subagents (actual: ${agentCount})`)
179
- }
180
- if (section.includes("34 static") && section.includes("scenarios")) {
181
- errors.push(`${doc}: current section still references 34 static scenarios (actual: ${staticScenarioCount})`)
182
- }
183
- }
128
+ const orchestrator = requireText(errors, readText(root, path.join("lib", "orchestrator-policy.mjs")), "lib/orchestrator-policy.mjs")
129
+ const legacyPolicy = requireText(errors, readText(root, path.join("global-config", "plugins", "ues-router", "policy-runtime.js")), "global-config/plugins/ues-router/policy-runtime.js")
130
+ const canonicalPolicy = requireText(errors, readText(root, path.join("lib", "task-policy.mjs")), "lib/task-policy.mjs")
131
+ if (orchestrator && !/from "\.\/task-policy\.mjs"/.test(orchestrator)) {
132
+ errors.push("lib/orchestrator-policy.mjs: must delegate to Pi-native lib/task-policy.mjs")
184
133
  }
185
-
186
- // 6. Check CI workflow
187
- const ciYaml = rText(".github/workflows/ci.yml")
188
- if (ciYaml.ok) {
189
- if (!ciYaml.value.includes("evals:v11:validate")) {
190
- errors.push(".github/workflows/ci.yml: missing evals:v11:validate job")
191
- }
192
- if (!/^\s*name:\s*CI Gate\s*$/m.test(ciYaml.value)) errors.push(".github/workflows/ci.yml: missing CI Gate aggregate job name")
193
- 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")
194
- if (!/if:\s*always\(\)/m.test(ciYaml.value)) errors.push(".github/workflows/ci.yml: aggregate gate must use if: always()")
195
- if (!ciYaml.value.includes("docs:check")) errors.push(".github/workflows/ci.yml: missing docs:check job")
196
- for (const check of ["evals:v12:validate", ...(expectedVersion.startsWith("13.") ? ["evals:v13"] : []), "evals:repo-scale:validate"]) {
197
- if (!ciYaml.value.includes(check)) errors.push(".github/workflows/ci.yml: missing " + check + " job")
198
- }
199
- } else {
200
- errors.push(ciYaml.error)
134
+ if (legacyPolicy && !/from "\.\.\/\.\.\/\.\.\/lib\/task-policy\.mjs"/.test(legacyPolicy)) {
135
+ errors.push("global-config/plugins/ues-router/policy-runtime.js: must remain a shim to lib/task-policy.mjs")
201
136
  }
202
-
203
- // 7. Check Security workflow
204
- const securityYaml = rText(".github/workflows/security.yml")
205
- if (securityYaml.ok) {
206
- if (!/^\s*name:\s*Security Gate\s*$/m.test(securityYaml.value)) errors.push(".github/workflows/security.yml: missing Security Gate aggregate job name")
207
- 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")
208
- } else {
209
- errors.push(securityYaml.error)
137
+ if (canonicalPolicy) {
138
+ if (!/export function classifyEngineeringTask/.test(canonicalPolicy)) errors.push("lib/task-policy.mjs: missing classifyEngineeringTask")
139
+ if (!/export function recoveryPolicyForAttempt/.test(canonicalPolicy)) errors.push("lib/task-policy.mjs: missing recoveryPolicyForAttempt")
210
140
  }
211
141
 
212
- // 8. Check publish workflow idempotency
213
- const publishYaml = rText(".github/workflows/publish.yml")
214
- if (publishYaml.ok) {
215
- if (!publishYaml.value.includes("already published")) {
216
- errors.push(".github/workflows/publish.yml: missing idempotency check for existing versions")
217
- }
218
- } else {
219
- errors.push(publishYaml.error)
142
+ if (pkg) {
143
+ const scripts = pkg.scripts || {}
144
+ if (scripts.test !== "node --test") errors.push("package.json: npm test must run portable full Node test discovery")
145
+ if (scripts["test:pi"] !== "node --test test/pi-package.test.mjs") errors.push("package.json: missing focused test:pi script")
146
+ if (scripts["docs:check"] !== "node scripts/check-release-consistency.mjs") errors.push("package.json: missing docs:check release-consistency script")
147
+ if (scripts["release:check-tag"] !== "node scripts/check-release-tag.mjs") errors.push("package.json: missing release:check-tag script")
148
+ if (scripts["eval:pi"] !== "node scripts/eval-pi.mjs") errors.push("package.json: missing Pi-native eval:pi script")
149
+ if (!String(scripts.ci || "").includes("npm run integrity")) errors.push("package.json: ci must include source-integrity gate")
150
+ if (scripts["runtime:exports"] !== "node scripts/check-runtime-exports.mjs") errors.push("package.json: missing runtime:exports import/export gate")
151
+ if (!String(scripts.ci || "").includes("npm run runtime:exports")) errors.push("package.json: ci must include runtime export gate")
152
+ if (!String(scripts.ci || "").includes("npm run docs:check")) errors.push("package.json: ci must include docs:check")
153
+ if (!String(scripts.ci || "").includes("npm test")) errors.push("package.json: ci must include full npm test")
154
+ if (!String(scripts.ci || "").includes("npm run smoke:packed")) errors.push("package.json: ci must include smoke:packed")
155
+ if (pkg.pi?.extensions?.[0] !== "./pi/extensions/ues.ts") errors.push("package.json: Pi extension entry drift")
156
+ if (!Array.isArray(pkg.pi?.skills) || !pkg.pi.skills.includes("./global-config/skills")) errors.push("package.json: Pi skills entry drift")
157
+ if (!Array.isArray(pkg.pi?.prompts) || !pkg.pi.prompts.includes("./pi/prompts/*.md")) errors.push("package.json: Pi prompts entry drift")
158
+ if (!Array.isArray(pkg.files) || !pkg.files.includes("global-config/AGENTS.md")) errors.push("package.json: installer runtime data global-config/AGENTS.md must be packed")
159
+ if (!pkg.files.includes("docs/V14.2-TURBO-WEAK-MODEL-RUNTIME.md")) errors.push("package.json: V14.2 runtime documentation must be packed")
160
+ if (scripts["smoke:packed"] !== "node scripts/smoke-packed-install.mjs") errors.push("package.json: missing smoke:packed integration script")
220
161
  }
221
162
 
222
- // 9. Check npm script docs:check exists
223
- if (pkg.ok) {
224
- const pkgScripts = pkg.value.scripts || {}
225
- if (!pkgScripts["docs:check"]) {
226
- warnings.push("package.json: missing docs:check npm script")
227
- }
228
- if (expectedVersion.startsWith("13.") && !pkgScripts["evals:v13"]) {
229
- errors.push("package.json: V13 requires evals:v13 regression script")
230
- }
231
- }
163
+ if (skillCount < 40) warnings.push(`skill catalog unexpectedly small: ${skillCount}`)
164
+ if (promptCount < 10) warnings.push(`Pi prompt catalog unexpectedly small: ${promptCount}`)
232
165
 
233
166
  return {
234
167
  pass: errors.length === 0,
235
168
  errors,
236
169
  warnings,
237
- version: expectedVersion,
170
+ version,
238
171
  skillCount,
239
172
  commandCount,
240
- subagentCount: agentCount,
173
+ subagentCount,
174
+ promptCount,
241
175
  staticScenarioCount,
242
176
  routerCaseCount,
243
177
  }
@@ -247,14 +181,14 @@ if (process.argv[1] === fileURLToPath(import.meta.url)) {
247
181
  const result = checkReleaseConsistency(process.env.UES_BUNDLE_ROOT || DEFAULT_ROOT)
248
182
  if (result.warnings.length) {
249
183
  console.warn("Warnings:")
250
- for (const w of result.warnings) console.warn(` WARN: ${w}`)
184
+ for (const warning of result.warnings) console.warn(` WARN: ${warning}`)
251
185
  }
252
186
  if (result.errors.length) {
253
187
  console.error("Release consistency check FAILED:")
254
- for (const e of result.errors) console.error(` - ${e}`)
188
+ for (const error of result.errors) console.error(` - ${error}`)
255
189
  process.exit(1)
256
190
  }
257
191
  console.log(
258
- `Release consistency check PASS: package=${result.version}, skills=${result.skillCount}, commands=${result.commandCount}, subagents=${result.subagentCount}`,
192
+ `Release consistency check PASS: package=${result.version}, skills=${result.skillCount}, prompts=${result.promptCount}, subagents=${result.subagentCount}`,
259
193
  )
260
- }
194
+ }
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+
3
+ import assert from "node:assert/strict"
4
+ import { readFile } from "node:fs/promises"
5
+ import path from "node:path"
6
+ import { fileURLToPath, pathToFileURL } from "node:url"
7
+
8
+ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
9
+ const extensionFiles = [
10
+ "pi/extensions/ues.ts",
11
+ "pi/extensions/ues-child-runtime.ts",
12
+ ]
13
+
14
+ function parseNamedLibImports(source) {
15
+ const rows = []
16
+ const pattern = /import\s*\{([^}]*)\}\s*from\s*["'](\.\.\/\.\.\/lib\/[^"']+\.mjs)["']\s*;?/g
17
+ let match
18
+ while ((match = pattern.exec(source))) {
19
+ const names = match[1]
20
+ .split(",")
21
+ .map((value) => value.trim())
22
+ .filter(Boolean)
23
+ .map((value) => {
24
+ const parts = value.split(/\s+as\s+/)
25
+ return { imported: parts[0].trim(), local: (parts[1] || parts[0]).trim() }
26
+ })
27
+ rows.push({ specifier: match[2], names })
28
+ }
29
+ return rows
30
+ }
31
+
32
+ const failures = []
33
+ let checked = 0
34
+ for (const relative of extensionFiles) {
35
+ const absolute = path.join(root, ...relative.split("/"))
36
+ const source = await readFile(absolute, "utf8")
37
+ for (const row of parseNamedLibImports(source)) {
38
+ const modulePath = path.resolve(path.dirname(absolute), row.specifier)
39
+ let imported
40
+ try {
41
+ imported = await import(pathToFileURL(modulePath).href)
42
+ } catch (error) {
43
+ failures.push(
44
+ `${relative}: unable to import ${row.specifier}: ${error instanceof Error ? error.message : String(error)}`,
45
+ )
46
+ continue
47
+ }
48
+ for (const name of row.names) {
49
+ checked += 1
50
+ if (!(name.imported in imported)) {
51
+ failures.push(
52
+ `${relative}: ${row.specifier} does not export named binding ${name.imported}`,
53
+ )
54
+ }
55
+ }
56
+ }
57
+ }
58
+
59
+ assert.deepEqual(
60
+ failures,
61
+ [],
62
+ "Pi extension runtime import/export validation failed:\n" +
63
+ failures.map((item) => "- " + item).join("\n"),
64
+ )
65
+
66
+ console.log(`Runtime exports passed for ${checked} Pi-extension named imports.`)