opencode-agent-skill 14.2.0-beta.1 → 15.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -18
- package/docs/PI-COMPAT.md +167 -3
- package/docs/V15-MANAGED-RUNTIME.md +128 -0
- package/global-config/agents/architect.md +63 -1
- package/global-config/agents/executor.md +7 -0
- package/global-config/agents/plan-checker.md +8 -1
- package/global-config/agents/verifier.md +3 -3
- package/global-config/skills/database-engineering/references/workflow.md +15 -0
- package/global-config/skills/engineering-orchestrator/references/long-horizon.md +21 -11
- package/lib/activity-deadline.mjs +70 -0
- package/lib/adaptive-context-budget.mjs +25 -5
- package/lib/affected-tests.mjs +1 -1
- package/lib/capability-fabric.mjs +40 -0
- package/lib/code-intelligence/edit-anchor.mjs +102 -0
- package/lib/code-intelligence/index.mjs +95 -0
- package/lib/code-intelligence/lsp-provider.mjs +189 -0
- package/lib/completion-auditor.mjs +102 -0
- package/lib/document-ingestion.mjs +60 -0
- package/lib/evidence-store.mjs +92 -8
- package/lib/execution-contract.mjs +579 -0
- package/lib/fast-verification-gate.mjs +69 -0
- package/lib/leaf-runtime-optimizer.mjs +76 -0
- package/lib/mcp-health.mjs +144 -0
- package/lib/mcp-tool-policy.mjs +19 -0
- package/lib/memory-engine.mjs +28 -0
- package/lib/pi-child-invocation.mjs +65 -0
- package/lib/pi-rpc-pool.mjs +61 -9
- package/lib/plan-salvage.mjs +124 -0
- package/lib/planning-speed-policy.mjs +131 -0
- package/lib/prompt-cache.mjs +26 -12
- package/lib/repo-graph.mjs +1 -1
- package/lib/repo-inspect.mjs +1 -0
- package/lib/reversible-context.mjs +49 -0
- package/lib/runtime-artifacts.mjs +42 -0
- package/lib/runtime-events.mjs +33 -1
- package/lib/safety.mjs +1 -0
- package/lib/semantic-index.mjs +1 -1
- package/lib/service-manager.mjs +526 -0
- package/lib/session-display.mjs +49 -0
- package/lib/task-engine.mjs +6 -10
- package/lib/task-graph.mjs +87 -0
- package/lib/task-policy.mjs +210 -8
- package/lib/trajectory.mjs +111 -1
- package/lib/turbo-fast-path.mjs +44 -0
- package/lib/workspace-fingerprint.mjs +2 -11
- package/lib/workspace-root.mjs +49 -0
- package/lib/worktree-sandbox.mjs +234 -11
- package/package.json +9 -6
- package/pi/extensions/ues-child-runtime.ts +300 -2
- package/pi/extensions/ues.ts +1887 -160
- package/scripts/check-release-consistency.mjs +25 -2
- package/scripts/check-source-integrity.mjs +532 -3
- package/scripts/eval-pi.mjs +76 -36
- package/scripts/smoke-pi-extension.mjs +1 -1
- package/pi/prompts/ues-run.md +0 -17
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
function bounded(value, fallback, min, max) {
|
|
2
|
+
const parsed = Number(value)
|
|
3
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return fallback
|
|
4
|
+
return Math.max(min, Math.min(max, Math.trunc(parsed)))
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function planningRuntimeBudget(role, attempt = 1, options = {}) {
|
|
8
|
+
const normalizedRole = String(role || "").replace(/^ues-/, "")
|
|
9
|
+
const normalizedAttempt = Math.max(1, Math.trunc(Number(attempt) || 1))
|
|
10
|
+
|
|
11
|
+
if (normalizedRole === "architect") {
|
|
12
|
+
const recovery = normalizedAttempt > 1
|
|
13
|
+
const deep = String(options.executionProfile || "") === "deep"
|
|
14
|
+
const largePrompt = Number(options.taskChars || 0) >= 2500
|
|
15
|
+
const initialHard = recovery ? 50_000 : 60_000
|
|
16
|
+
const absoluteHard = recovery
|
|
17
|
+
? 95_000
|
|
18
|
+
: deep || largePrompt
|
|
19
|
+
? 150_000
|
|
20
|
+
: 120_000
|
|
21
|
+
return {
|
|
22
|
+
hardTimeoutMs: bounded(
|
|
23
|
+
recovery ? options.architectRecoveryHardTimeoutMs : options.architectHardTimeoutMs,
|
|
24
|
+
initialHard,
|
|
25
|
+
30_000,
|
|
26
|
+
5 * 60_000,
|
|
27
|
+
),
|
|
28
|
+
absoluteHardTimeoutMs: bounded(
|
|
29
|
+
recovery ? options.architectRecoveryAbsoluteHardTimeoutMs : options.architectAbsoluteHardTimeoutMs,
|
|
30
|
+
absoluteHard,
|
|
31
|
+
initialHard,
|
|
32
|
+
6 * 60_000,
|
|
33
|
+
),
|
|
34
|
+
activityExtensionMs: bounded(
|
|
35
|
+
recovery ? options.architectRecoveryActivityExtensionMs : options.architectActivityExtensionMs,
|
|
36
|
+
recovery ? 25_000 : 35_000,
|
|
37
|
+
10_000,
|
|
38
|
+
90_000,
|
|
39
|
+
),
|
|
40
|
+
activityWindowMs: bounded(
|
|
41
|
+
options.architectActivityWindowMs,
|
|
42
|
+
20_000,
|
|
43
|
+
5_000,
|
|
44
|
+
60_000,
|
|
45
|
+
),
|
|
46
|
+
idleTimeoutMs: bounded(
|
|
47
|
+
recovery ? options.architectRecoveryIdleTimeoutMs : options.architectIdleTimeoutMs,
|
|
48
|
+
recovery ? 28_000 : 40_000,
|
|
49
|
+
10_000,
|
|
50
|
+
2 * 60_000,
|
|
51
|
+
),
|
|
52
|
+
softSteerMs: bounded(
|
|
53
|
+
options.architectSoftSteerMs,
|
|
54
|
+
30_000,
|
|
55
|
+
15_000,
|
|
56
|
+
2 * 60_000,
|
|
57
|
+
),
|
|
58
|
+
maxExplorationTools: bounded(options.architectMaxExplorationTools, 16, 8, 80),
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (normalizedRole === "plan-checker") {
|
|
63
|
+
const recovery = normalizedAttempt > 1
|
|
64
|
+
const initialHard = recovery ? 45_000 : 70_000
|
|
65
|
+
return {
|
|
66
|
+
hardTimeoutMs: bounded(
|
|
67
|
+
recovery ? options.planCheckerRecoveryHardTimeoutMs : options.planCheckerHardTimeoutMs,
|
|
68
|
+
initialHard,
|
|
69
|
+
30_000,
|
|
70
|
+
5 * 60_000,
|
|
71
|
+
),
|
|
72
|
+
absoluteHardTimeoutMs: bounded(
|
|
73
|
+
recovery ? options.planCheckerRecoveryAbsoluteHardTimeoutMs : options.planCheckerAbsoluteHardTimeoutMs,
|
|
74
|
+
recovery ? 80_000 : 130_000,
|
|
75
|
+
initialHard,
|
|
76
|
+
5 * 60_000,
|
|
77
|
+
),
|
|
78
|
+
activityExtensionMs: bounded(
|
|
79
|
+
recovery ? options.planCheckerRecoveryActivityExtensionMs : options.planCheckerActivityExtensionMs,
|
|
80
|
+
recovery ? 20_000 : 30_000,
|
|
81
|
+
10_000,
|
|
82
|
+
60_000,
|
|
83
|
+
),
|
|
84
|
+
activityWindowMs: bounded(
|
|
85
|
+
options.planCheckerActivityWindowMs,
|
|
86
|
+
20_000,
|
|
87
|
+
5_000,
|
|
88
|
+
60_000,
|
|
89
|
+
),
|
|
90
|
+
idleTimeoutMs: bounded(
|
|
91
|
+
recovery ? options.planCheckerRecoveryIdleTimeoutMs : options.planCheckerIdleTimeoutMs,
|
|
92
|
+
recovery ? 24_000 : 38_000,
|
|
93
|
+
10_000,
|
|
94
|
+
2 * 60_000,
|
|
95
|
+
),
|
|
96
|
+
softSteerMs: bounded(
|
|
97
|
+
recovery ? options.planCheckerRecoverySoftSteerMs : options.planCheckerSoftSteerMs,
|
|
98
|
+
recovery ? 18_000 : 35_000,
|
|
99
|
+
10_000,
|
|
100
|
+
2 * 60_000,
|
|
101
|
+
),
|
|
102
|
+
maxExplorationTools: bounded(
|
|
103
|
+
recovery ? options.planCheckerRecoveryMaxExplorationTools : options.planCheckerMaxExplorationTools,
|
|
104
|
+
recovery ? 6 : 10,
|
|
105
|
+
4,
|
|
106
|
+
40,
|
|
107
|
+
),
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return null
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function shouldSoftSteerArchitect(progress = {}, budget = null) {
|
|
115
|
+
if (!budget) return false
|
|
116
|
+
const elapsedMs = Number(progress.elapsedMs || 0)
|
|
117
|
+
const toolCalls = Number(progress.toolCalls || 0)
|
|
118
|
+
const idleMs = Number(progress.idleMs || 0)
|
|
119
|
+
|
|
120
|
+
if (budget.softSteerMs && elapsedMs >= budget.softSteerMs) return true
|
|
121
|
+
if (budget.maxExplorationTools && toolCalls >= budget.maxExplorationTools) return true
|
|
122
|
+
|
|
123
|
+
// If the model has gone quiet after doing real exploration, ask it to emit
|
|
124
|
+
// the plan before the hard idle watchdog has to kill the worker.
|
|
125
|
+
return toolCalls > 0 && idleMs >= Math.max(10_000, Math.floor((budget.idleTimeoutMs || 30_000) * 0.65))
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
export function shouldSoftSteerPlanningRole(progress = {}, budget = null) {
|
|
130
|
+
return shouldSoftSteerArchitect(progress, budget)
|
|
131
|
+
}
|
package/lib/prompt-cache.mjs
CHANGED
|
@@ -5,31 +5,35 @@ function canonical(value) {
|
|
|
5
5
|
if (!value || typeof value !== "object") return value
|
|
6
6
|
return Object.fromEntries(Object.keys(value).sort().map((key) => [key, canonical(value[key])]))
|
|
7
7
|
}
|
|
8
|
-
|
|
9
|
-
function stringify(value)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return createHash("sha256").update(stringify(value)).digest("hex")
|
|
8
|
+
function stringify(value) { return typeof value === "string" ? value : JSON.stringify(canonical(value)) }
|
|
9
|
+
function digest(value) { return createHash("sha256").update(stringify(value)).digest("hex") }
|
|
10
|
+
function chars(value) { return stringify(value ?? "").length }
|
|
11
|
+
function finiteTokenCount(value) {
|
|
12
|
+
const number = Number(value)
|
|
13
|
+
return Number.isFinite(number) && number >= 0 ? number : null
|
|
15
14
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
function changedStableKeys(previous, current) {
|
|
16
|
+
const left = previous?.stable || {}
|
|
17
|
+
const right = current?.stable || {}
|
|
18
|
+
return [...new Set([...Object.keys(left), ...Object.keys(right)])]
|
|
19
|
+
.filter((key) => digest(left[key]) !== digest(right[key]))
|
|
20
|
+
.sort()
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
export function buildPromptEnvelope(input = {}) {
|
|
24
|
+
const memorySnapshot = input.memorySnapshot || null
|
|
22
25
|
const stable = {
|
|
23
26
|
invariants: input.invariants || "",
|
|
24
27
|
role: input.role || "",
|
|
25
28
|
skills: input.skills || [],
|
|
26
29
|
projectFacts: input.projectFacts || {},
|
|
27
30
|
toolPolicy: input.toolPolicy || {},
|
|
31
|
+
memorySnapshot,
|
|
28
32
|
}
|
|
29
33
|
const dynamic = {
|
|
30
34
|
task: input.task || {},
|
|
31
35
|
evidence: input.evidence || [],
|
|
32
|
-
memories: input.memories || [],
|
|
36
|
+
memories: memorySnapshot ? [] : (input.memories || []),
|
|
33
37
|
contextHints: input.contextHints || {},
|
|
34
38
|
recentFailure: input.recentFailure || null,
|
|
35
39
|
nextAction: input.nextAction || null,
|
|
@@ -45,18 +49,28 @@ export function buildPromptEnvelope(input = {}) {
|
|
|
45
49
|
dynamicHash: digest(dynamic),
|
|
46
50
|
stableChars,
|
|
47
51
|
dynamicChars,
|
|
52
|
+
cacheableChars: stableChars,
|
|
48
53
|
cacheableRatio: stableChars + dynamicChars ? stableChars / (stableChars + dynamicChars) : 0,
|
|
54
|
+
cacheReadTokens: finiteTokenCount(input.cacheReadTokens),
|
|
55
|
+
cacheWriteTokens: finiteTokenCount(input.cacheWriteTokens),
|
|
49
56
|
}
|
|
50
57
|
}
|
|
51
58
|
|
|
52
|
-
export function comparePromptEnvelopes(previous, current) {
|
|
59
|
+
export function comparePromptEnvelopes(previous, current, usage = {}) {
|
|
53
60
|
const stableReused = Boolean(previous?.stablePrefixHash && previous.stablePrefixHash === current?.stablePrefixHash)
|
|
54
61
|
const repeatedStableChars = stableReused ? Number(current?.stableChars || 0) : 0
|
|
62
|
+
const mutated = stableReused ? [] : changedStableKeys(previous, current)
|
|
55
63
|
return {
|
|
56
64
|
schemaVersion: 1,
|
|
57
65
|
stableReused,
|
|
58
66
|
repeatedStableChars,
|
|
59
67
|
avoidableRepeatedChars: stableReused ? 0 : Math.min(Number(previous?.stableChars || 0), Number(current?.stableChars || 0)),
|
|
60
68
|
currentCacheableRatio: Number(current?.cacheableRatio || 0),
|
|
69
|
+
cacheableChars: Number(current?.cacheableChars ?? current?.stableChars ?? 0),
|
|
70
|
+
dynamicChars: Number(current?.dynamicChars || 0),
|
|
71
|
+
cacheReadTokens: finiteTokenCount(usage.cacheReadTokens ?? current?.cacheReadTokens),
|
|
72
|
+
cacheWriteTokens: finiteTokenCount(usage.cacheWriteTokens ?? current?.cacheWriteTokens),
|
|
73
|
+
prefixMutationReason: stableReused ? null : (mutated.length ? mutated.join(",") : "stable-prefix-changed"),
|
|
74
|
+
mutatedStableKeys: mutated,
|
|
61
75
|
}
|
|
62
76
|
}
|
package/lib/repo-graph.mjs
CHANGED
|
@@ -6,7 +6,7 @@ const SKIP = new Set([
|
|
|
6
6
|
".git", "node_modules", ".next", "dist", "build", "coverage", ".venv", "venv",
|
|
7
7
|
"Pods", "DerivedData", ".gradle", ".idea", ".cache", ".turbo", "target", "obj",
|
|
8
8
|
".ues-work", ".ues-cache", ".ues-traces", ".ues-learning", ".ues-dashboard",
|
|
9
|
-
".ues-sandboxes", ".ues-memory", ".ues-evals",
|
|
9
|
+
".ues-sandboxes", ".ues-memory", ".ues-evals", ".ues-services",
|
|
10
10
|
])
|
|
11
11
|
|
|
12
12
|
const SOURCE_EXTENSIONS = new Set([
|
package/lib/repo-inspect.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import { spawnSync } from "node:child_process"
|
|
|
6
6
|
const SKIP_DIRS = new Set([
|
|
7
7
|
".git", "node_modules", ".next", "dist", "build", "coverage", ".venv", "venv",
|
|
8
8
|
"Pods", "DerivedData", ".gradle", ".idea", ".cache", ".turbo", "target", "bin", "obj",
|
|
9
|
+
".ues-services",
|
|
9
10
|
])
|
|
10
11
|
|
|
11
12
|
const TEXT_EXTENSIONS = new Set([
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { putEvidence, getEvidence, getEvidenceSelected } from "./evidence-store.mjs"
|
|
2
|
+
|
|
3
|
+
function normalize(value) { return String(value ?? "").replace(/\r\n/g, "\n").replace(/\r/g, "\n") }
|
|
4
|
+
function significantLines(text) {
|
|
5
|
+
const lines = normalize(text).split("\n")
|
|
6
|
+
const scored = lines.map((line, index) => {
|
|
7
|
+
const trimmed = line.trim(); let score = 0
|
|
8
|
+
if (/^#{1,6}\s/.test(trimmed)) score += 8
|
|
9
|
+
if (/^(?:[-*+] |\d+[.)]\s)/.test(trimmed)) score += 5
|
|
10
|
+
if (/\b(?:error|fail|warning|todo|fixme|pass|test|result|summary|important|must|required)\b/i.test(trimmed)) score += 4
|
|
11
|
+
if (/^(?:export|import|class|function|def|interface|type|CREATE|ALTER)\b/i.test(trimmed)) score += 3
|
|
12
|
+
if (trimmed.length > 0 && trimmed.length <= 180) score += 1
|
|
13
|
+
return { index, line, score }
|
|
14
|
+
})
|
|
15
|
+
return { lines, scored }
|
|
16
|
+
}
|
|
17
|
+
function summary(text, maxChars) {
|
|
18
|
+
const { lines, scored } = significantLines(text)
|
|
19
|
+
if (normalize(text).length <= maxChars) return normalize(text)
|
|
20
|
+
const wanted = new Set(scored.filter((row) => row.score > 0).sort((a,b) => b.score - a.score || a.index - b.index).slice(0,80).map((row) => row.index))
|
|
21
|
+
for (let i = Math.max(0, lines.length - 8); i < lines.length; i += 1) wanted.add(i)
|
|
22
|
+
let out = ""
|
|
23
|
+
for (const index of [...wanted].sort((a,b) => a-b)) {
|
|
24
|
+
const candidate = (out ? out + "\n" : "") + lines[index]
|
|
25
|
+
if (candidate.length > maxChars) break
|
|
26
|
+
out = candidate
|
|
27
|
+
}
|
|
28
|
+
return out || normalize(text).slice(0, maxChars)
|
|
29
|
+
}
|
|
30
|
+
export async function compactContext(root, content, options = {}) {
|
|
31
|
+
const raw = normalize(content)
|
|
32
|
+
const stored = await putEvidence(root, raw, { kind: options.kind || "context-block", source: options.source || "ues-context", summary: options.summary || "Reversible raw context block" })
|
|
33
|
+
return { schemaVersion: 1, ref: stored.ref, originalChars: raw.length, levels: { T1: summary(raw, Math.max(512, Number(options.t1Chars || 1600))), T2: summary(raw, Math.max(1200, Number(options.t2Chars || 5000))), T3: summary(raw, Math.max(2400, Number(options.t3Chars || 12000))) } }
|
|
34
|
+
}
|
|
35
|
+
export async function expandContext(root, ref, options = {}) {
|
|
36
|
+
return getEvidenceSelected(root, ref, { start: Math.max(0, Number(options.start || 0)), maxBytes: Math.max(1, Math.min(128_000, Number(options.maxBytes || 16_000))) })
|
|
37
|
+
}
|
|
38
|
+
export async function searchContext(root, ref, query, options = {}) {
|
|
39
|
+
const maxBytes = Math.max(16_000, Math.min(4 * 1024 * 1024, Number(options.maxBytes || 512_000)))
|
|
40
|
+
const evidence = await getEvidence(root, ref, { maxBytes })
|
|
41
|
+
const source = normalize(evidence?.content ?? evidence ?? "")
|
|
42
|
+
const terms = [...new Set(String(query || "").toLowerCase().split(/[^\p{L}\p{N}_$.-]+/u).filter((item) => item.length >= 2))].slice(0, 16)
|
|
43
|
+
const lines = source.split("\n"); const radius = Math.max(0, Math.min(12, Number(options.radius || 2))); const maxMatches = Math.max(1, Math.min(50, Number(options.maxMatches || 10))); const hits = []
|
|
44
|
+
for (let index = 0; index < lines.length && hits.length < maxMatches; index += 1) {
|
|
45
|
+
const lower = lines[index].toLowerCase(); const matched = terms.filter((term) => lower.includes(term)); if (!matched.length) continue
|
|
46
|
+
hits.push({ line: index + 1, terms: matched, excerpt: lines.slice(Math.max(0,index-radius), Math.min(lines.length,index+radius+1)).join("\n") })
|
|
47
|
+
}
|
|
48
|
+
return { schemaVersion: 1, ref, query: String(query || ""), terms, hits, truncatedSource: source.length >= maxBytes }
|
|
49
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export const UES_RUNTIME_DIRS = Object.freeze([
|
|
2
|
+
".ues-cache",
|
|
3
|
+
".ues-traces",
|
|
4
|
+
".ues-work",
|
|
5
|
+
".ues-learning",
|
|
6
|
+
".ues-dashboard",
|
|
7
|
+
".ues-sandboxes",
|
|
8
|
+
".ues-memory",
|
|
9
|
+
".ues-evals",
|
|
10
|
+
".ues-services",
|
|
11
|
+
])
|
|
12
|
+
|
|
13
|
+
export function normalizeRuntimePath(value) {
|
|
14
|
+
return String(value || "")
|
|
15
|
+
.replaceAll("\\", "/")
|
|
16
|
+
.replace(/^\.\//, "")
|
|
17
|
+
.replace(/^\/+/, "")
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function isUesRuntimeArtifactPath(value) {
|
|
21
|
+
const normalized = normalizeRuntimePath(value)
|
|
22
|
+
if (!normalized) return false
|
|
23
|
+
return UES_RUNTIME_DIRS.some(
|
|
24
|
+
(dir) => normalized === dir || normalized.startsWith(dir + "/"),
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function sourceFacingPaths(values = []) {
|
|
29
|
+
return [...new Set(
|
|
30
|
+
(values || [])
|
|
31
|
+
.map(normalizeRuntimePath)
|
|
32
|
+
.filter(Boolean)
|
|
33
|
+
.filter((value) => !isUesRuntimeArtifactPath(value)),
|
|
34
|
+
)]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function sourceGitPathspecs() {
|
|
38
|
+
return [
|
|
39
|
+
".",
|
|
40
|
+
...UES_RUNTIME_DIRS.map((dir) => ":(exclude)" + dir + "/**"),
|
|
41
|
+
]
|
|
42
|
+
}
|
package/lib/runtime-events.mjs
CHANGED
|
@@ -1,7 +1,39 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto"
|
|
2
|
-
import { appendFile, readFile } from "node:fs/promises"
|
|
2
|
+
import { appendFile, readFile, stat, writeFile } from "node:fs/promises"
|
|
3
|
+
|
|
4
|
+
const DEFAULT_MAX_EVENT_FILE_BYTES = 4 * 1024 * 1024
|
|
5
|
+
const DEFAULT_RETAIN_EVENT_BYTES = 2 * 1024 * 1024
|
|
6
|
+
|
|
7
|
+
async function compactRuntimeEventFile(file, options = {}) {
|
|
8
|
+
const maxBytes = Math.max(
|
|
9
|
+
256 * 1024,
|
|
10
|
+
Math.min(64 * 1024 * 1024, Number(options.maxBytes || process.env.UES_EVENT_LOG_MAX_BYTES || DEFAULT_MAX_EVENT_FILE_BYTES)),
|
|
11
|
+
)
|
|
12
|
+
const retainBytes = Math.max(
|
|
13
|
+
128 * 1024,
|
|
14
|
+
Math.min(maxBytes, Number(options.retainBytes || DEFAULT_RETAIN_EVENT_BYTES)),
|
|
15
|
+
)
|
|
16
|
+
const info = await stat(file).catch(() => null)
|
|
17
|
+
if (!info?.isFile() || info.size < maxBytes) return false
|
|
18
|
+
|
|
19
|
+
const raw = await readFile(file)
|
|
20
|
+
let kept = raw.subarray(Math.max(0, raw.length - retainBytes))
|
|
21
|
+
const newline = kept.indexOf(0x0a)
|
|
22
|
+
if (newline >= 0 && raw.length > retainBytes) kept = kept.subarray(newline + 1)
|
|
23
|
+
const marker = Buffer.from(JSON.stringify({
|
|
24
|
+
schemaVersion: 1,
|
|
25
|
+
id: randomUUID(),
|
|
26
|
+
type: "runtime-events.compacted",
|
|
27
|
+
at: new Date().toISOString(),
|
|
28
|
+
previousBytes: raw.length,
|
|
29
|
+
retainedBytes: kept.length,
|
|
30
|
+
}) + "\n")
|
|
31
|
+
await writeFile(file, Buffer.concat([marker, kept]))
|
|
32
|
+
return true
|
|
33
|
+
}
|
|
3
34
|
|
|
4
35
|
export async function appendRuntimeEvent(file, type, data = {}) {
|
|
36
|
+
await compactRuntimeEventFile(file).catch(() => false)
|
|
5
37
|
const event = {
|
|
6
38
|
schemaVersion: 1,
|
|
7
39
|
id: randomUUID(),
|
package/lib/safety.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const RULES = [
|
|
2
2
|
{ id: "git-force", pattern: /\bgit\s+(?:push\b[^\n]*(?:--force(?:-with-lease)?|(?:^|\s)-f(?:\s|$))|reset\s+--hard|clean\s+-[^\n]*f)/i },
|
|
3
|
+
{ id: "git-discard-work", pattern: /\bgit\s+(?:restore\b|checkout\s+--(?:\s|$)|stash(?:\s|$))/i },
|
|
3
4
|
{ id: "history-rewrite", pattern: /\bgit\s+(?:rebase\b|filter-branch\b|filter-repo\b)/i },
|
|
4
5
|
{ id: "publish", pattern: /\b(?:npm\s+publish|pnpm\s+publish|yarn\s+npm\s+publish)\b/i },
|
|
5
6
|
{ id: "destructive-files", pattern: /(?:^|[;&|]\s*)(?:rm\s+-[^\n]*r[^\n]*f|rmdir\s+\/s|del\s+\/s|remove-item\b[^\n]*-recurse[^\n]*-force)/i },
|
package/lib/semantic-index.mjs
CHANGED
|
@@ -12,7 +12,7 @@ const SOURCE_EXTENSIONS = new Set([
|
|
|
12
12
|
const SKIP_DIRS = new Set([
|
|
13
13
|
".git", "node_modules", ".next", "dist", "build", "coverage", ".venv", "venv",
|
|
14
14
|
"Pods", "DerivedData", ".gradle", ".idea", ".cache", ".turbo", "target", "obj",
|
|
15
|
-
".ues-work", ".ues-learning", ".ues-memory", ".ues-dashboard", ".ues-sandboxes", ".ues-cache", ".ues-traces",
|
|
15
|
+
".ues-work", ".ues-learning", ".ues-memory", ".ues-dashboard", ".ues-sandboxes", ".ues-cache", ".ues-traces", ".ues-services",
|
|
16
16
|
])
|
|
17
17
|
const STOP_IDENTIFIERS = new Set([
|
|
18
18
|
"const","let","var","function","class","interface","type","export","import","from","return",
|