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.
- package/README.md +1557 -606
- package/bin/ocskill.mjs +172 -24
- package/docs/OPENCODE-COMPAT.md +34 -95
- package/docs/PI-COMPAT.md +188 -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/commands/run.md +27 -20
- package/global-config/plugins/ues-router/command-runtime.js +54 -0
- package/global-config/plugins/ues-router/index.js +30 -24
- 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 +336 -0
- package/lib/capability-registry.mjs +9 -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/dynamic-workflow.mjs +3 -1
- package/lib/evidence-store.mjs +82 -1
- package/lib/hierarchical-context.mjs +215 -0
- package/lib/memory-engine.mjs +465 -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 +2 -0
- package/lib/repo-graph.mjs +53 -2
- 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 +66 -5
- package/lib/task-policy.mjs +235 -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 +238 -0
- package/pi/extensions/ues.ts +3200 -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 +184 -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 -405
- 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 -75
- package/docs/V7-INTELLIGENCE-RUNTIME.md +0 -166
- package/docs/V8-INTELLIGENCE-RELIABILITY.md +0 -206
- package/docs/V9-SPEED-INTELLIGENCE.md +0 -102
|
@@ -29,6 +29,60 @@ export function normalizeUesPromptPaste(text) {
|
|
|
29
29
|
return value
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
export function policySourceForPromptAlias(promptAlias, promptText) {
|
|
33
|
+
if (!promptAlias) return normalizeUesPromptPaste(promptText).trim()
|
|
34
|
+
|
|
35
|
+
const args = String(promptAlias.arguments || "").trim()
|
|
36
|
+
if (promptAlias.alias === "ues-resume") {
|
|
37
|
+
return [
|
|
38
|
+
"Resume an existing durable UES execution.",
|
|
39
|
+
args,
|
|
40
|
+
].filter(Boolean).join("\n")
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return args || `/${promptAlias.alias}`
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function promptAliasTextForPolicy(promptAlias, policy) {
|
|
47
|
+
if (!promptAlias) return null
|
|
48
|
+
if (promptAlias.alias !== "ues-run") return promptAlias.text
|
|
49
|
+
|
|
50
|
+
const args = String(promptAlias.arguments || "").trim()
|
|
51
|
+
const mode = String(policy?.mode || "").toLowerCase()
|
|
52
|
+
const risk = String(policy?.risk || "").toLowerCase()
|
|
53
|
+
const profile = String(policy?.executionProfile || policy?.profile?.name || "").toLowerCase()
|
|
54
|
+
const isDeep = mode === "long-horizon" || risk === "high" || profile === "deep"
|
|
55
|
+
const isFast = !isDeep && (profile === "fast" || mode === "inline")
|
|
56
|
+
const isStandard = !isDeep && (profile === "standard" || mode === "standard")
|
|
57
|
+
|
|
58
|
+
if (isFast) {
|
|
59
|
+
return [
|
|
60
|
+
"UES V2 prompt alias: /ues-run. Adaptive policy selected FAST from the actual user request.",
|
|
61
|
+
"Preserve the user's exact requested outcome and response constraints.",
|
|
62
|
+
"Do not initialize .ues-work, create SPEC/PLAN state, inspect the repository, dispatch subagents, or run verification unless the request itself requires repository work or machine-checkable evidence.",
|
|
63
|
+
"If the request is directly answerable, answer it directly now.",
|
|
64
|
+
"",
|
|
65
|
+
"User request:",
|
|
66
|
+
args,
|
|
67
|
+
].join("\n").trim()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (isStandard) {
|
|
71
|
+
return [
|
|
72
|
+
"UES V2 prompt alias: /ues-run. Adaptive policy selected STANDARD from the actual user request.",
|
|
73
|
+
"Preserve the user's exact requested outcome and approval boundaries.",
|
|
74
|
+
"Use targeted repository evidence, bounded edits, and targeted + affected verification.",
|
|
75
|
+
"Do not create durable .ues-work state, plan gates, integration gates, or parallel workers unless new evidence justifies reclassification to DEEP/high-risk.",
|
|
76
|
+
"If evidence materially widens scope or risk, re-run ocskill task-policy on a concise updated summary before escalating.",
|
|
77
|
+
"",
|
|
78
|
+
"User request:",
|
|
79
|
+
args,
|
|
80
|
+
].join("\n").trim()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return promptAlias.text
|
|
84
|
+
}
|
|
85
|
+
|
|
32
86
|
export function policyPromptForCli(text, maxChars = 12_000) {
|
|
33
87
|
const raw = normalizeUesPromptPaste(text).trim()
|
|
34
88
|
const limit = Math.max(2_000, Number(maxChars) || 12_000)
|
|
@@ -8,7 +8,13 @@ import { runtimeCapabilities } from "./capabilities.js"
|
|
|
8
8
|
import { parallelRootBaseline, runEventDrivenDAG } from "./parallel-runtime.js"
|
|
9
9
|
import { readProjectJson, readProjectText } from "./text-runtime.js"
|
|
10
10
|
import { extractVerifierVerdict } from "./verifier-runtime.js"
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
expandUesPromptAlias,
|
|
13
|
+
policyPromptForCli,
|
|
14
|
+
policySourceForPromptAlias,
|
|
15
|
+
promptAliasTextForPolicy,
|
|
16
|
+
} from "./command-runtime.js"
|
|
17
|
+
import { classifyEngineeringTask } from "./policy-runtime.js"
|
|
12
18
|
import {
|
|
13
19
|
budgetToolResult,
|
|
14
20
|
classifyProviderFailure,
|
|
@@ -51,6 +57,13 @@ function spawnHidden(command, args, options = {}) {
|
|
|
51
57
|
})
|
|
52
58
|
}
|
|
53
59
|
|
|
60
|
+
function bestEffortProgress(tool, status) {
|
|
61
|
+
try {
|
|
62
|
+
const pending = tool?.progress?.({ status })
|
|
63
|
+
if (pending && typeof pending.catch === "function") pending.catch(() => {})
|
|
64
|
+
} catch {}
|
|
65
|
+
}
|
|
66
|
+
|
|
54
67
|
function findWindowsCommand(name) {
|
|
55
68
|
const result = spawnHidden("where", [name], { encoding: "utf8" })
|
|
56
69
|
if (result.status !== 0 || !result.stdout) return null
|
|
@@ -566,7 +579,7 @@ export default {
|
|
|
566
579
|
},
|
|
567
580
|
options: { namespace: "ues", codemode: true },
|
|
568
581
|
execute: async (input) => ({
|
|
569
|
-
content:
|
|
582
|
+
content: JSON.stringify(classifyEngineeringTask(input.text), null, 2),
|
|
570
583
|
}),
|
|
571
584
|
})
|
|
572
585
|
editor.add({
|
|
@@ -975,7 +988,7 @@ export default {
|
|
|
975
988
|
...(started?.contextPack?.task?.acceptance || []),
|
|
976
989
|
started?.contextPack?.task?.risk ? "risk: " + started.contextPack.task.risk : null,
|
|
977
990
|
].filter(Boolean).join(" ")
|
|
978
|
-
const taskPolicy =
|
|
991
|
+
const taskPolicy = classifyEngineeringTask(taskText)
|
|
979
992
|
appendTrace(traceID, "dispatch.started", {
|
|
980
993
|
slug: input.slug,
|
|
981
994
|
task: input.task,
|
|
@@ -1473,7 +1486,7 @@ export default {
|
|
|
1473
1486
|
if (result.sandbox?.dir) {
|
|
1474
1487
|
try { runOcskill(["sandbox", "remove", result.sandbox.dir, projectRoot, "--force", "--delete-branch"], projectRoot) } catch {}
|
|
1475
1488
|
}
|
|
1476
|
-
|
|
1489
|
+
bestEffortProgress(tool, "parallel task " + task.id + " verified and integrated")
|
|
1477
1490
|
return { integration, deterministicReceipts, receipt, completed }
|
|
1478
1491
|
} catch (error) {
|
|
1479
1492
|
if (!durableCompleted) {
|
|
@@ -1489,7 +1502,7 @@ export default {
|
|
|
1489
1502
|
},
|
|
1490
1503
|
onEvent: (event) => {
|
|
1491
1504
|
if (["task.started", "task.completed", "task.failed"].includes(event.type)) {
|
|
1492
|
-
|
|
1505
|
+
bestEffortProgress(tool, "parallel " + event.type + " " + event.task)
|
|
1493
1506
|
}
|
|
1494
1507
|
},
|
|
1495
1508
|
})
|
|
@@ -1538,9 +1551,17 @@ export default {
|
|
|
1538
1551
|
const config = routerConfig()
|
|
1539
1552
|
if (!config.enabled) return
|
|
1540
1553
|
|
|
1541
|
-
const
|
|
1554
|
+
const originalPromptText = String(event.prompt?.text || "")
|
|
1555
|
+
const promptAlias = expandUesPromptAlias(originalPromptText, COMMAND_TEMPLATE_DIR)
|
|
1556
|
+
const routingText = promptAlias
|
|
1557
|
+
? (promptAlias.arguments || `/${promptAlias.alias}`)
|
|
1558
|
+
: originalPromptText
|
|
1559
|
+
const policySource = policySourceForPromptAlias(promptAlias, originalPromptText)
|
|
1560
|
+
const policyInput = policyPromptForCli(policySource)
|
|
1561
|
+
const policy = classifyEngineeringTask(policyInput.text)
|
|
1562
|
+
|
|
1542
1563
|
if (promptAlias && event.prompt) {
|
|
1543
|
-
event.prompt.text = promptAlias
|
|
1564
|
+
event.prompt.text = promptAliasTextForPolicy(promptAlias, policy)
|
|
1544
1565
|
event.metadata = {
|
|
1545
1566
|
...event.metadata,
|
|
1546
1567
|
uesPromptAlias: {
|
|
@@ -1548,27 +1569,12 @@ export default {
|
|
|
1548
1569
|
sourceName: promptAlias.sourceName,
|
|
1549
1570
|
preferredAgent: promptAlias.agent,
|
|
1550
1571
|
transport: "session.prompt",
|
|
1572
|
+
adaptiveProfile: policy?.executionProfile || policy?.profile?.name || null,
|
|
1551
1573
|
},
|
|
1552
1574
|
}
|
|
1553
1575
|
}
|
|
1554
1576
|
|
|
1555
|
-
const promptText = String(event.prompt?.text ||
|
|
1556
|
-
const routingText = promptAlias
|
|
1557
|
-
? (promptAlias.arguments || `/${promptAlias.alias}`)
|
|
1558
|
-
: promptText
|
|
1559
|
-
const policySource = promptAlias
|
|
1560
|
-
? [
|
|
1561
|
-
["ues-run", "ues-resume"].includes(promptAlias.alias)
|
|
1562
|
-
? "Explicit long-horizon engineering request."
|
|
1563
|
-
: `UES command /${promptAlias.alias}.`,
|
|
1564
|
-
promptAlias.arguments,
|
|
1565
|
-
].filter(Boolean).join("\n")
|
|
1566
|
-
: routingText
|
|
1567
|
-
const policyInput = policyPromptForCli(policySource)
|
|
1568
|
-
let policy = null
|
|
1569
|
-
try {
|
|
1570
|
-
policy = runOcskillJSON(["task-policy", policyInput.text], projectRoot)
|
|
1571
|
-
} catch {}
|
|
1577
|
+
const promptText = String(event.prompt?.text || originalPromptText)
|
|
1572
1578
|
const intent = classifyIntent(routingText, routingFacts)
|
|
1573
1579
|
const effectiveMaxSkills = Math.max(
|
|
1574
1580
|
1,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Legacy OpenCode router compatibility shim.
|
|
2
|
+
// The canonical task policy is Pi-native and lives in lib/task-policy.mjs.
|
|
3
|
+
// Keep this file only so older installations do not fork policy behavior.
|
|
4
|
+
export {
|
|
5
|
+
classifyEngineeringTask,
|
|
6
|
+
recoveryPolicyForAttempt,
|
|
7
|
+
} from "../../../lib/task-policy.mjs"
|
|
@@ -2,6 +2,16 @@ function add(list, id) {
|
|
|
2
2
|
if (!list.includes(id)) list.push(id)
|
|
3
3
|
}
|
|
4
4
|
|
|
5
|
+
const HIGH_RISK_MUTATION = /((?:fix|change|modify|update|alter|migrate|drop|truncate|delete|remove|rotate|deploy|publish|push|sửa|thay đổi|cập nhật|xóa|xoá|di trú|chuyển đổi|triển khai).{0,64}(?:\bauth\b|authorization|authentication|security|permission|payment(?: handling| flow)?|schema|database|production|public api|secret|credential|phân quyền|bảo mật|thanh toán|cơ sở dữ liệu|api công khai|bí mật|thông tin xác thực)|(?:\bauth\b|authorization|authentication|security|permission|payment(?: handling| flow)?|schema|database|production|public api|secret|credential|phân quyền|bảo mật|thanh toán|cơ sở dữ liệu|api công khai|bí mật|thông tin xác thực).{0,64}(?:fix|change|modify|update|alter|migrate|drop|truncate|delete|remove|rotate|deploy|publish|push|sửa|thay đổi|cập nhật|xóa|xoá|di trú|chuyển đổi|triển khai)|database migration|schema migration|migrate database|migrate schema|drop table|truncate table|deploy(?:ment)?\s+(?:to\s+)?production|production\s+deploy(?:ment)?|rotate\s+(?:secret|credential)|breaking\s+(?:change\s+to\s+)?(?:public\s+)?api|npm publish|git push|force push|reset --hard|git clean)/i
|
|
6
|
+
|
|
7
|
+
function riskTextFor(value) {
|
|
8
|
+
return String(value || "")
|
|
9
|
+
.replace(/\b(?:do not|don't|without)\s+(?:edit|modify|change|write|delete|remove)[^.\n]*/gi, "")
|
|
10
|
+
.replace(/\b(?:no|read[- ]only)\s+(?:edits?|changes?|writes?)[^.\n]*/gi, "")
|
|
11
|
+
.replace(/không\s+(?:sửa|chỉnh sửa|thay đổi|ghi|xóa|xoá)[^.\n]*/gi, "")
|
|
12
|
+
.replace(/chỉ\s+đọc[^.\n]*/gi, "")
|
|
13
|
+
}
|
|
14
|
+
|
|
5
15
|
const PROCESS_SKILLS = new Set([
|
|
6
16
|
"ues-engineering-orchestrator",
|
|
7
17
|
"ues-long-task-state",
|
|
@@ -90,8 +100,8 @@ export function classifyIntent(text, facts = {}) {
|
|
|
90
100
|
if (/(refactor|cleanup|restructure|refactor toàn bộ)/.test(value)) add(actions, "refactor")
|
|
91
101
|
if (/(latest|current docs|documentation|release notes|version compatibility|dependency|package version|api changed|tài liệu mới nhất|phiên bản mới|tương thích phiên bản|package mới)/.test(value)) add(actions, "research")
|
|
92
102
|
|
|
93
|
-
const risky =
|
|
94
|
-
const longHorizon = value.length > 700 || /(large task|big task|long[- ]running|multi[- ]file|cross[- ]module|whole (?:repo|repository|project)|entire (?:repo|repository|project)|full refactor|refactor all|migrate all|resume this work|toàn bộ (?:repo|repository|dự án)|nhiều file|nhiều module|refactor toàn bộ|tiếp tục công việc)/.test(value)
|
|
103
|
+
const risky = HIGH_RISK_MUTATION.test(riskTextFor(value))
|
|
104
|
+
const longHorizon = value.length > 700 || /(large task|big task|long[- ]running|multi[- ]file|cross[- ]module|whole (?:repo|repository|project)|entire (?:repo|repository|project)|full refactor|refactor all|migrate all|multi[- ]step migration|migration across|resume this work|toàn bộ (?:repo|repository|dự án)|nhiều file|nhiều module|refactor toàn bộ|tiếp tục công việc)/.test(value)
|
|
95
105
|
const nonTrivial = value.length > 220 || risky || actions.length > 0
|
|
96
106
|
|
|
97
107
|
const feedbackDomains = [...new Set((facts.feedbackDomains || []).filter((item) => domains.includes(item)))]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ecommerce-engineering
|
|
3
|
-
description: Build/review ecommerce and marketplace systems: catalog, sellers, carts, checkout, orders, inventory, pricing, images, and traceability.
|
|
3
|
+
description: "Build/review ecommerce and marketplace systems: catalog, sellers, carts, checkout, orders, inventory, pricing, images, and traceability."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Ecommerce Engineering
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: file-upload-engineering
|
|
3
|
-
description: Implement file/image uploads safely: validation, storage, naming, URLs, cleanup, permissions, progress, and errors.
|
|
3
|
+
description: "Implement file/image uploads safely: validation, storage, naming, URLs, cleanup, permissions, progress, and errors."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# File Upload Engineering
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: git-safety
|
|
3
|
-
description: Use Git safely: inspect status/diffs, preserve user work, stage intentional files, commit clearly, and avoid destructive history operations.
|
|
3
|
+
description: "Use Git safely: inspect status/diffs, preserve user work, stage intentional files, commit clearly, and avoid destructive history operations."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Git Safety
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: nestjs-engineering
|
|
3
|
-
description: Work on NestJS apps: modules, controllers, providers, DTO validation, guards, interceptors, persistence, and tests.
|
|
3
|
+
description: "Work on NestJS apps: modules, controllers, providers, DTO validation, guards, interceptors, persistence, and tests."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Nestjs Engineering
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: performance-engineering
|
|
3
|
-
description: Diagnose and improve performance using evidence: rendering, database, network, memory, caching, bundles, concurrency, and hot paths.
|
|
3
|
+
description: "Diagnose and improve performance using evidence: rendering, database, network, memory, caching, bundles, concurrency, and hot paths."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Performance Engineering
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: react-native-engineering
|
|
3
|
-
description: Work on React Native/Expo apps: components, hooks, navigation, styling, APIs, native modules, Android/iOS build failures, platform behavior, and performance with version-aware verification.
|
|
3
|
+
description: "Work on React Native/Expo apps: components, hooks, navigation, styling, APIs, native modules, Android/iOS build failures, platform behavior, and performance with version-aware verification."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# React Native Engineering
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: rest-api-design
|
|
3
|
-
description: Design/review REST APIs: resources, methods, status codes, pagination, validation, errors, versioning, and idempotency.
|
|
3
|
+
description: "Design/review REST APIs: resources, methods, status codes, pagination, validation, errors, versioning, and idempotency."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Rest Api Design
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ui-ux-engineering
|
|
3
|
-
description: Improve production UI/UX: hierarchy, responsive layout, components, forms, states, accessibility, realistic content, and design consistency.
|
|
3
|
+
description: "Improve production UI/UX: hierarchy, responsive layout, components, forms, states, accessibility, realistic content, and design consistency."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Ui Ux Engineering
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
const ROLE_TARGETS = Object.freeze({
|
|
2
|
+
fast: {
|
|
3
|
+
architect: 8_000,
|
|
4
|
+
"plan-checker": 6_000,
|
|
5
|
+
executor: 6_000,
|
|
6
|
+
debugger: 8_000,
|
|
7
|
+
verifier: 4_500,
|
|
8
|
+
"integration-verifier": 8_000,
|
|
9
|
+
"visual-verifier": 5_000,
|
|
10
|
+
reviewer: 5_000,
|
|
11
|
+
critic: 6_000,
|
|
12
|
+
"codebase-mapper": 6_000,
|
|
13
|
+
researcher: 6_000,
|
|
14
|
+
"merge-arbiter": 8_000,
|
|
15
|
+
},
|
|
16
|
+
standard: {
|
|
17
|
+
architect: 12_000,
|
|
18
|
+
"plan-checker": 10_000,
|
|
19
|
+
executor: 11_000,
|
|
20
|
+
debugger: 14_000,
|
|
21
|
+
verifier: 8_000,
|
|
22
|
+
"integration-verifier": 12_000,
|
|
23
|
+
"visual-verifier": 8_000,
|
|
24
|
+
reviewer: 8_000,
|
|
25
|
+
critic: 10_000,
|
|
26
|
+
"codebase-mapper": 10_000,
|
|
27
|
+
researcher: 10_000,
|
|
28
|
+
"merge-arbiter": 12_000,
|
|
29
|
+
},
|
|
30
|
+
deep: {
|
|
31
|
+
architect: 30_000,
|
|
32
|
+
"plan-checker": 24_000,
|
|
33
|
+
executor: 26_000,
|
|
34
|
+
debugger: 32_000,
|
|
35
|
+
verifier: 20_000,
|
|
36
|
+
"integration-verifier": 30_000,
|
|
37
|
+
"visual-verifier": 18_000,
|
|
38
|
+
reviewer: 20_000,
|
|
39
|
+
critic: 24_000,
|
|
40
|
+
"codebase-mapper": 28_000,
|
|
41
|
+
researcher: 24_000,
|
|
42
|
+
"merge-arbiter": 30_000,
|
|
43
|
+
},
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
function clamp(value, fallback, min, max) {
|
|
47
|
+
const parsed = Number(value)
|
|
48
|
+
if (!Number.isFinite(parsed)) return fallback
|
|
49
|
+
return Math.max(min, Math.min(max, Math.trunc(parsed)))
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function adaptiveContextBudget(taskPolicy = {}, role = "executor", attempt = 1, options = {}) {
|
|
53
|
+
const base = clamp(
|
|
54
|
+
taskPolicy.contextBudget ?? taskPolicy.profile?.contextBudget,
|
|
55
|
+
20_000,
|
|
56
|
+
4_000,
|
|
57
|
+
48_000,
|
|
58
|
+
)
|
|
59
|
+
const profile = String(taskPolicy.executionProfile || taskPolicy.profile?.name || "standard")
|
|
60
|
+
const highRisk = taskPolicy.risk === "high" || taskPolicy.risk === "critical"
|
|
61
|
+
|
|
62
|
+
// High-risk work keeps the original evidence budget. Turbo mode must not trade
|
|
63
|
+
// away security/payment/schema evidence for latency.
|
|
64
|
+
if (highRisk || options.disabled === true) {
|
|
65
|
+
return {
|
|
66
|
+
schemaVersion: 1,
|
|
67
|
+
budget: base,
|
|
68
|
+
baseBudget: base,
|
|
69
|
+
adaptive: false,
|
|
70
|
+
reason: highRisk ? "high-risk-preserves-base-budget" : "disabled",
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const table = ROLE_TARGETS[profile] || ROLE_TARGETS.standard
|
|
75
|
+
const target = clamp(table?.[role], base, 4_000, base)
|
|
76
|
+
const normalizedAttempt = Math.max(1, Math.trunc(Number(attempt || 1)))
|
|
77
|
+
|
|
78
|
+
// Failed attempts expand deterministically back toward the policy ceiling.
|
|
79
|
+
let budget = target
|
|
80
|
+
if (normalizedAttempt === 2) budget = Math.min(base, Math.max(target, Math.round(target * 1.5)))
|
|
81
|
+
else if (normalizedAttempt >= 3) budget = base
|
|
82
|
+
|
|
83
|
+
if (options.contextInsufficient === true) {
|
|
84
|
+
budget = Math.min(base, Math.max(budget, Math.round(target * 1.75)))
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
schemaVersion: 1,
|
|
89
|
+
budget,
|
|
90
|
+
baseBudget: base,
|
|
91
|
+
adaptive: budget < base,
|
|
92
|
+
profile,
|
|
93
|
+
role,
|
|
94
|
+
attempt: normalizedAttempt,
|
|
95
|
+
reason: budget < base ? "role-bounded-expand-on-failure" : "policy-ceiling",
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { existsSync } from "node:fs"
|
|
2
|
+
import { readFile, readdir, stat } from "node:fs/promises"
|
|
3
|
+
import path from "node:path"
|
|
4
|
+
import { spawnSync } from "node:child_process"
|
|
5
|
+
import { runtimeWorkspaceFingerprint } from "./workspace-fingerprint.mjs"
|
|
6
|
+
|
|
7
|
+
const TEST_RE = /(?:^|[/.\\])(?:__tests__|tests?|spec)(?:[/.\\]|$)|\.(?:test|spec|e2e-spec)\.[cm]?[jt]sx?$/i
|
|
8
|
+
const SOURCE_EXT = new Set([".js",".jsx",".mjs",".cjs",".ts",".tsx",".py",".java",".kt",".kts",".cs",".go",".rs",".dart",".swift"])
|
|
9
|
+
const SKIP = new Set([".git","node_modules",".next","dist","build","coverage",".venv","venv","target","Pods","DerivedData",".gradle",".ues-cache",".ues-work",".ues-sandboxes",".ues-traces",".ues-learning",".ues-dashboard",".ues-memory",".ues-evals"])
|
|
10
|
+
const AFFECTED_TEST_CACHE = new Map()
|
|
11
|
+
const AFFECTED_TEST_INFLIGHT = new Map()
|
|
12
|
+
|
|
13
|
+
function git(root, args) {
|
|
14
|
+
return spawnSync("git", args, { cwd: root, encoding: "utf8", maxBuffer: 8 * 1024 * 1024 })
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function normalize(file) {
|
|
18
|
+
return String(file || "").replaceAll("\\", "/").replace(/^\.\//, "")
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function stem(file) {
|
|
22
|
+
return path.basename(file)
|
|
23
|
+
.replace(/\.(?:test|spec|e2e-spec)(?=\.)/i, "")
|
|
24
|
+
.replace(/\.[^.]+$/, "")
|
|
25
|
+
.toLowerCase()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function tokens(file) {
|
|
29
|
+
return [...new Set(normalize(file).toLowerCase().split(/[^a-z0-9]+/).filter((x) => x.length >= 3))]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function walk(root, options = {}) {
|
|
33
|
+
const maxFiles = Math.max(200, Number(options.maxFiles || 6000))
|
|
34
|
+
const rows = []
|
|
35
|
+
async function visit(dir, depth) {
|
|
36
|
+
if (rows.length >= maxFiles || depth > 14) return
|
|
37
|
+
const entries = await readdir(dir, { withFileTypes: true }).catch(() => [])
|
|
38
|
+
for (const entry of entries) {
|
|
39
|
+
if (rows.length >= maxFiles) break
|
|
40
|
+
if (entry.isDirectory() && SKIP.has(entry.name)) continue
|
|
41
|
+
const full = path.join(dir, entry.name)
|
|
42
|
+
if (entry.isDirectory()) await visit(full, depth + 1)
|
|
43
|
+
else if (entry.isFile()) rows.push(full)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
await visit(root, 0)
|
|
47
|
+
return rows
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function gitChangedFiles(root = process.cwd()) {
|
|
51
|
+
root = path.resolve(root)
|
|
52
|
+
const inside = git(root, ["rev-parse", "--is-inside-work-tree"])
|
|
53
|
+
if (inside.status !== 0) return []
|
|
54
|
+
|
|
55
|
+
const names = new Set()
|
|
56
|
+
for (const args of [
|
|
57
|
+
["diff", "--name-only", "--"],
|
|
58
|
+
["diff", "--cached", "--name-only", "--"],
|
|
59
|
+
["ls-files", "--others", "--exclude-standard"],
|
|
60
|
+
]) {
|
|
61
|
+
const result = git(root, args)
|
|
62
|
+
if (result.status !== 0) continue
|
|
63
|
+
for (const row of String(result.stdout || "").split(/\r?\n/)) {
|
|
64
|
+
const file = normalize(row.trim())
|
|
65
|
+
if (file) names.add(file)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return [...names]
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function scoreTest(testFile, changedFile, content = "") {
|
|
72
|
+
const test = normalize(testFile).toLowerCase()
|
|
73
|
+
const changed = normalize(changedFile).toLowerCase()
|
|
74
|
+
let score = 0
|
|
75
|
+
const reasons = []
|
|
76
|
+
const changedStem = stem(changed)
|
|
77
|
+
const testStem = stem(test)
|
|
78
|
+
|
|
79
|
+
if (changedStem && testStem.includes(changedStem)) {
|
|
80
|
+
score += 35
|
|
81
|
+
reasons.push("same-stem")
|
|
82
|
+
}
|
|
83
|
+
const testDir = path.posix.dirname(test)
|
|
84
|
+
const changedDir = path.posix.dirname(changed)
|
|
85
|
+
if (testDir === changedDir) {
|
|
86
|
+
score += 20
|
|
87
|
+
reasons.push("same-directory")
|
|
88
|
+
} else if (testDir.startsWith(changedDir + "/") || changedDir.startsWith(testDir + "/")) {
|
|
89
|
+
score += 10
|
|
90
|
+
reasons.push("nearby-directory")
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const changedTokens = tokens(changed)
|
|
94
|
+
const overlap = changedTokens.filter((token) => test.includes(token)).length
|
|
95
|
+
if (overlap) {
|
|
96
|
+
score += Math.min(20, overlap * 4)
|
|
97
|
+
reasons.push("path-token-overlap")
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const base = path.basename(changed).replace(/\.[^.]+$/, "")
|
|
101
|
+
if (base.length >= 3 && content.toLowerCase().includes(base.toLowerCase())) {
|
|
102
|
+
score += 25
|
|
103
|
+
reasons.push("content-reference")
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return { score, reasons }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function nearestPackage(root, file) {
|
|
110
|
+
let dir = path.dirname(path.resolve(root, file))
|
|
111
|
+
const base = path.resolve(root)
|
|
112
|
+
while (dir === base || dir.startsWith(base + path.sep)) {
|
|
113
|
+
const packageFile = path.join(dir, "package.json")
|
|
114
|
+
if (existsSync(packageFile)) {
|
|
115
|
+
try {
|
|
116
|
+
return { dir, json: JSON.parse(await readFile(packageFile, "utf8")) }
|
|
117
|
+
} catch {}
|
|
118
|
+
}
|
|
119
|
+
if (dir === base) break
|
|
120
|
+
dir = path.dirname(dir)
|
|
121
|
+
}
|
|
122
|
+
return null
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function packageManager(root) {
|
|
126
|
+
if (existsSync(path.join(root, "pnpm-lock.yaml"))) return "pnpm"
|
|
127
|
+
if (existsSync(path.join(root, "yarn.lock"))) return "yarn"
|
|
128
|
+
if (existsSync(path.join(root, "bun.lock")) || existsSync(path.join(root, "bun.lockb"))) return "bun"
|
|
129
|
+
return "npm"
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function targetedCommand(root, pkg, testFile) {
|
|
133
|
+
const script = String(pkg?.json?.scripts?.test || "")
|
|
134
|
+
if (!script || !/(jest|vitest|node\s+--test|tsx\s+--test)/i.test(script)) return null
|
|
135
|
+
const manager = packageManager(root)
|
|
136
|
+
const relativeDir = normalize(path.relative(root, pkg.dir)) || "."
|
|
137
|
+
const relativeTest = normalize(path.relative(pkg.dir, path.resolve(root, testFile)))
|
|
138
|
+
|
|
139
|
+
if (manager === "pnpm") {
|
|
140
|
+
return { command: "pnpm", args: ["--dir", relativeDir, "run", "test", "--", relativeTest], confidence: "high" }
|
|
141
|
+
}
|
|
142
|
+
if (manager === "yarn") {
|
|
143
|
+
return { command: "yarn", args: ["--cwd", relativeDir, "test", relativeTest], confidence: "high" }
|
|
144
|
+
}
|
|
145
|
+
if (manager === "bun") {
|
|
146
|
+
return { command: "bun", args: ["--cwd", relativeDir, "run", "test", "--", relativeTest], confidence: "high" }
|
|
147
|
+
}
|
|
148
|
+
return { command: "npm", args: ["--prefix", relativeDir, "test", "--", relativeTest], confidence: "high" }
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export async function resolveAffectedTests(root = process.cwd(), options = {}) {
|
|
152
|
+
root = path.resolve(root)
|
|
153
|
+
const changed = (options.changedFiles || gitChangedFiles(root))
|
|
154
|
+
.map(normalize)
|
|
155
|
+
.filter((file) => SOURCE_EXT.has(path.extname(file).toLowerCase()) && !TEST_RE.test(file))
|
|
156
|
+
|
|
157
|
+
if (!changed.length) {
|
|
158
|
+
return {
|
|
159
|
+
schemaVersion: 1,
|
|
160
|
+
root,
|
|
161
|
+
changedFiles: [],
|
|
162
|
+
tests: [],
|
|
163
|
+
suggestedCommands: [],
|
|
164
|
+
truncated: false,
|
|
165
|
+
cacheHit: false,
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const limit = Math.max(1, Math.min(40, Number(options.limit || 12)))
|
|
170
|
+
let fingerprint = String(options.workspaceFingerprint || "")
|
|
171
|
+
if (!fingerprint || fingerprint === "unknown") {
|
|
172
|
+
try { fingerprint = runtimeWorkspaceFingerprint(root) } catch { fingerprint = "" }
|
|
173
|
+
}
|
|
174
|
+
if (fingerprint === "unknown") fingerprint = ""
|
|
175
|
+
|
|
176
|
+
const cacheKey = JSON.stringify([
|
|
177
|
+
root,
|
|
178
|
+
fingerprint || "no-fingerprint",
|
|
179
|
+
[...changed].sort(),
|
|
180
|
+
Number(options.maxFiles || 6000),
|
|
181
|
+
limit,
|
|
182
|
+
])
|
|
183
|
+
|
|
184
|
+
if (fingerprint && AFFECTED_TEST_CACHE.has(cacheKey)) {
|
|
185
|
+
return { ...AFFECTED_TEST_CACHE.get(cacheKey), cacheHit: true }
|
|
186
|
+
}
|
|
187
|
+
if (fingerprint && AFFECTED_TEST_INFLIGHT.has(cacheKey)) {
|
|
188
|
+
const value = await AFFECTED_TEST_INFLIGHT.get(cacheKey)
|
|
189
|
+
return { ...value, cacheHit: true, cacheCoalesced: true }
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const compute = async () => {
|
|
193
|
+
const files = await walk(root, options)
|
|
194
|
+
const tests = files
|
|
195
|
+
.map((file) => normalize(path.relative(root, file)))
|
|
196
|
+
.filter((file) => TEST_RE.test(file))
|
|
197
|
+
|
|
198
|
+
const ranked = []
|
|
199
|
+
for (const testFile of tests) {
|
|
200
|
+
const info = await stat(path.join(root, testFile)).catch(() => null)
|
|
201
|
+
const content = info?.size && info.size <= 512 * 1024
|
|
202
|
+
? await readFile(path.join(root, testFile), "utf8").catch(() => "")
|
|
203
|
+
: ""
|
|
204
|
+
let best = { score: 0, reasons: [], changedFile: null }
|
|
205
|
+
for (const changedFile of changed) {
|
|
206
|
+
const current = scoreTest(testFile, changedFile, content)
|
|
207
|
+
if (current.score > best.score) best = { ...current, changedFile }
|
|
208
|
+
}
|
|
209
|
+
if (best.score > 0) ranked.push({ path: testFile, ...best })
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
ranked.sort((a, b) => b.score - a.score || a.path.localeCompare(b.path))
|
|
213
|
+
const selected = ranked.slice(0, limit)
|
|
214
|
+
const suggestedCommands = []
|
|
215
|
+
const seen = new Set()
|
|
216
|
+
|
|
217
|
+
for (const item of selected.slice(0, 8)) {
|
|
218
|
+
const pkg = await nearestPackage(root, item.path)
|
|
219
|
+
const command = pkg ? targetedCommand(root, pkg, item.path) : null
|
|
220
|
+
if (!command) continue
|
|
221
|
+
const key = JSON.stringify([command.command, command.args])
|
|
222
|
+
if (seen.has(key)) continue
|
|
223
|
+
seen.add(key)
|
|
224
|
+
suggestedCommands.push({ ...command, test: item.path })
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
schemaVersion: 1,
|
|
229
|
+
root,
|
|
230
|
+
changedFiles: changed,
|
|
231
|
+
tests: selected,
|
|
232
|
+
suggestedCommands,
|
|
233
|
+
truncated: ranked.length > selected.length,
|
|
234
|
+
cacheHit: false,
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const pending = compute()
|
|
239
|
+
if (fingerprint) AFFECTED_TEST_INFLIGHT.set(cacheKey, pending)
|
|
240
|
+
|
|
241
|
+
try {
|
|
242
|
+
const result = await pending
|
|
243
|
+
if (fingerprint) {
|
|
244
|
+
AFFECTED_TEST_CACHE.set(cacheKey, result)
|
|
245
|
+
while (AFFECTED_TEST_CACHE.size > 24) {
|
|
246
|
+
const oldest = AFFECTED_TEST_CACHE.keys().next().value
|
|
247
|
+
if (!oldest) break
|
|
248
|
+
AFFECTED_TEST_CACHE.delete(oldest)
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return result
|
|
252
|
+
} finally {
|
|
253
|
+
if (fingerprint) AFFECTED_TEST_INFLIGHT.delete(cacheKey)
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export function clearAffectedTestCache() {
|
|
258
|
+
AFFECTED_TEST_CACHE.clear()
|
|
259
|
+
AFFECTED_TEST_INFLIGHT.clear()
|
|
260
|
+
}
|