opencode-agent-skill 13.0.0-beta.2 → 14.4.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 +1571 -607
- package/bin/ocskill.mjs +172 -24
- package/docs/OPENCODE-COMPAT.md +34 -97
- package/docs/PI-COMPAT.md +203 -0
- package/docs/V14-CONTEXT-MEMORY-FABRIC.md +70 -0
- package/docs/V14.1-QUALITY-PERFORMANCE-FABRIC.md +114 -0
- package/docs/V14.2-TURBO-WEAK-MODEL-RUNTIME.md +448 -0
- package/evals/v14/tasks.json +46 -0
- package/global-config/agents/executor.md +7 -0
- package/global-config/agents/visual-verifier.md +22 -3
- package/global-config/plugins/ues-router/index.js +13 -8
- package/global-config/plugins/ues-router/policy-runtime.js +7 -0
- package/global-config/plugins/ues-router/router.js +12 -2
- package/global-config/skills/ecommerce-engineering/SKILL.md +1 -1
- package/global-config/skills/file-upload-engineering/SKILL.md +1 -1
- package/global-config/skills/git-safety/SKILL.md +1 -1
- package/global-config/skills/nestjs-engineering/SKILL.md +1 -1
- package/global-config/skills/performance-engineering/SKILL.md +1 -1
- package/global-config/skills/react-native-engineering/SKILL.md +1 -1
- package/global-config/skills/rest-api-design/SKILL.md +1 -1
- package/global-config/skills/ui-ux-engineering/SKILL.md +1 -1
- package/lib/adaptive-context-budget.mjs +97 -0
- package/lib/affected-tests.mjs +260 -0
- package/lib/benchmark-confidence.mjs +41 -2
- package/lib/browser-mcp-routing.mjs +166 -0
- package/lib/capability-fabric.mjs +359 -0
- package/lib/capability-registry.mjs +9 -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 +82 -0
- package/lib/context-engine-v11.mjs +65 -1
- package/lib/context-graph-rank.mjs +118 -0
- package/lib/context-manifest.mjs +97 -18
- package/lib/control-center.mjs +19 -1
- package/lib/document-ingestion.mjs +60 -0
- package/lib/dynamic-workflow.mjs +3 -1
- package/lib/evidence-store.mjs +82 -1
- package/lib/fast-verification-gate.mjs +69 -0
- package/lib/hierarchical-context.mjs +215 -0
- package/lib/mcp-health.mjs +144 -0
- package/lib/mcp-tool-policy.mjs +19 -0
- package/lib/memory-engine.mjs +493 -0
- package/lib/model-performance.mjs +33 -8
- package/lib/model-policy.mjs +3 -3
- package/lib/orchestrator-policy.mjs +5 -209
- package/lib/performance-fabric.mjs +229 -0
- package/lib/pi-rpc-pool.mjs +433 -0
- package/lib/process-hang-detector.mjs +83 -0
- package/lib/process-supervisor.mjs +193 -0
- package/lib/prompt-cache.mjs +27 -11
- package/lib/repo-graph.mjs +53 -2
- package/lib/reversible-context.mjs +49 -0
- package/lib/runtime-config.mjs +31 -0
- package/lib/safety.mjs +132 -0
- package/lib/semantic-index.mjs +52 -3
- package/lib/skill-compiler.mjs +128 -0
- package/lib/skill-quality.mjs +48 -2
- package/lib/task-engine.mjs +62 -5
- package/lib/task-policy.mjs +291 -0
- package/lib/verification-broker.mjs +284 -0
- package/lib/verification-command.mjs +111 -0
- package/lib/windows-shim.mjs +35 -0
- package/lib/workspace-fingerprint.mjs +198 -0
- package/package.json +52 -42
- package/pi/extensions/ues-child-runtime.ts +393 -0
- package/pi/extensions/ues.ts +3327 -0
- package/pi/prompts/ues-audit.md +9 -0
- package/pi/prompts/ues-critique.md +9 -0
- package/pi/prompts/ues-debug.md +9 -0
- package/pi/prompts/ues-feature.md +9 -0
- package/pi/prompts/ues-fix.md +9 -0
- package/pi/prompts/ues-plan.md +9 -0
- package/pi/prompts/ues-research.md +9 -0
- package/pi/prompts/ues-resume.md +9 -0
- package/pi/prompts/ues-review.md +7 -0
- package/pi/prompts/ues-run.md +17 -0
- package/pi/prompts/ues-verify.md +9 -0
- package/scripts/check-release-consistency.mjs +119 -185
- package/scripts/check-runtime-exports.mjs +66 -0
- package/scripts/check-source-integrity.mjs +246 -0
- package/scripts/eval-pi.mjs +492 -0
- package/scripts/install.mjs +16 -0
- package/scripts/smoke-package-closure.mjs +110 -0
- package/scripts/smoke-packed-install.mjs +24 -11
- package/scripts/smoke-pi-extension.mjs +144 -0
- package/scripts/uninstall.mjs +44 -0
- package/CHANGELOG.md +0 -415
- package/docs/DETERMINISTIC-TOOLS.md +0 -105
- package/docs/ENGINEERING-DESIGN.md +0 -194
- package/docs/EVALS.md +0 -158
- package/docs/GITHUB-RULESET.md +0 -50
- package/docs/NPM-PUBLISH.md +0 -116
- package/docs/RESEARCH-SOURCES.md +0 -37
- package/docs/TRACE-SCHEMA.md +0 -122
- package/docs/V11-PERCEPTION-ADAPTIVE-EXECUTION.md +0 -75
- package/docs/V11-PERCEPTION-ADAPTIVE.md +0 -220
- package/docs/V12-WEAK-MODEL-INTELLIGENCE.md +0 -27
- package/docs/V13-PARALLEL-WEAK-MODEL-RUNTIME.md +0 -86
- package/docs/V7-INTELLIGENCE-RUNTIME.md +0 -166
- package/docs/V8-INTELLIGENCE-RELIABILITY.md +0 -206
- 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 (
|
|
17
|
-
return {
|
|
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
|
|
30
|
-
const
|
|
31
|
-
if (!existsSync(
|
|
32
|
-
const entries = readdirSync(
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
59
|
-
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
77
|
-
const
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
|
88
|
-
const
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
errors.push(
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
|
|
134
|
-
if (
|
|
135
|
-
const
|
|
136
|
-
|
|
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
|
-
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
-
|
|
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
|
-
|
|
204
|
-
|
|
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
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
if (
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
errors.push(
|
|
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
|
-
|
|
223
|
-
if (
|
|
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
|
|
170
|
+
version,
|
|
238
171
|
skillCount,
|
|
239
172
|
commandCount,
|
|
240
|
-
subagentCount
|
|
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
|
|
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
|
|
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},
|
|
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.`)
|