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
package/package.json
CHANGED
|
@@ -1,61 +1,50 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-agent-skill",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "14.4.0",
|
|
4
|
+
"description": "Pi Agent engineering runtime with code intelligence, hash-anchored editing, verified persistent memory, health-aware capability routing, reversible context, and evidence-gated completion",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
+
"ues": "bin/ocskill.mjs",
|
|
7
8
|
"ocskill": "bin/ocskill.mjs"
|
|
8
9
|
},
|
|
9
10
|
"files": [
|
|
10
11
|
"bin/ocskill.mjs",
|
|
11
12
|
"lib/",
|
|
13
|
+
"global-config/AGENTS.md",
|
|
14
|
+
"global-config/skills/",
|
|
15
|
+
"global-config/agents/",
|
|
16
|
+
"global-config/commands/",
|
|
17
|
+
"global-config/plugins/",
|
|
18
|
+
"pi/",
|
|
12
19
|
"scripts/",
|
|
13
|
-
"global-config/",
|
|
14
20
|
"evals/",
|
|
15
|
-
"docs/",
|
|
21
|
+
"docs/V14-CONTEXT-MEMORY-FABRIC.md",
|
|
22
|
+
"docs/V14.1-QUALITY-PERFORMANCE-FABRIC.md",
|
|
23
|
+
"docs/V14.2-TURBO-WEAK-MODEL-RUNTIME.md",
|
|
24
|
+
"docs/PI-COMPAT.md",
|
|
25
|
+
"docs/OPENCODE-COMPAT.md",
|
|
16
26
|
"README.md",
|
|
17
|
-
"CHANGELOG.md",
|
|
18
27
|
"LICENSE"
|
|
19
28
|
],
|
|
20
29
|
"scripts": {
|
|
21
30
|
"syntax": "node scripts/syntax-check.mjs",
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"evals:live:validate": "node scripts/validate-live-suite.mjs",
|
|
25
|
-
"test": "node --test test/*.test.mjs",
|
|
26
|
-
"ci": "npm run syntax && npm run validate && npm run docs:check && npm run evals && npm run evals:router && npm run evals:v11:validate && npm run evals:v12:validate && npm run evals:v13 && npm run evals:repo-scale:validate && npm run evals:live:validate && npm run evals:long:validate && npm run evals:polyglot:validate && npm test && npm pack --dry-run && npm run smoke:pack && npm run smoke:plain-install",
|
|
27
|
-
"postinstall": "node scripts/install.mjs",
|
|
28
|
-
"preuninstall": "node scripts/uninstall.mjs",
|
|
29
|
-
"prepublishOnly": "npm run ci",
|
|
30
|
-
"evals:live": "node scripts/eval-live.mjs",
|
|
31
|
-
"smoke:pack": "node scripts/smoke-packed-install.mjs",
|
|
32
|
-
"inspect:stack": "node scripts/detect-stack.mjs",
|
|
33
|
-
"inspect:tests": "node scripts/detect-test-commands.mjs",
|
|
34
|
-
"inspect:repo": "node scripts/repo-map.mjs",
|
|
35
|
-
"inspect:impact": "node scripts/impact-map.mjs",
|
|
36
|
-
"inspect:evidence": "node scripts/collect-evidence.mjs",
|
|
37
|
-
"inspect:git": "node scripts/check-working-tree.mjs",
|
|
38
|
-
"evals:report": "node scripts/eval-report.mjs",
|
|
39
|
-
"evals:router": "node scripts/eval-router.mjs",
|
|
40
|
-
"evals:long:validate": "node scripts/validate-live-suite.mjs --suite long",
|
|
41
|
-
"evals:long": "node scripts/eval-live.mjs --suite long",
|
|
42
|
-
"dashboard": "node scripts/control-center.mjs",
|
|
43
|
-
"evals:matrix": "node scripts/eval-matrix.mjs",
|
|
44
|
-
"smoke:plain-install": "node scripts/smoke-plain-install.mjs",
|
|
31
|
+
"test": "node --test",
|
|
32
|
+
"test:pi": "node --test test/pi-package.test.mjs",
|
|
45
33
|
"docs:check": "node scripts/check-release-consistency.mjs",
|
|
46
34
|
"release:check-tag": "node scripts/check-release-tag.mjs",
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
35
|
+
"smoke:pi": "node scripts/smoke-pi-extension.mjs",
|
|
36
|
+
"smoke:package": "node scripts/smoke-package-closure.mjs",
|
|
37
|
+
"eval:pi": "node scripts/eval-pi.mjs",
|
|
38
|
+
"ci": "npm run integrity && npm run runtime:exports && npm run syntax && npm test && npm run docs:check && npm pack --dry-run && npm run smoke:pi && npm run smoke:package && npm run smoke:packed",
|
|
39
|
+
"prepublishOnly": "npm run ci",
|
|
40
|
+
"smoke:packed": "node scripts/smoke-packed-install.mjs",
|
|
41
|
+
"eval:v14": "node --test test/capability-fabric-v14.test.mjs test/hierarchical-context-v14.test.mjs test/memory-engine-v14.test.mjs test/context-engine-v14.test.mjs test/task-engine-v14-context.test.mjs test/cli-v14.test.mjs test/v14-contract.test.mjs test/performance-fabric-v14.test.mjs test/browser-mcp-routing-v14.test.mjs test/process-hang-detector-v14.test.mjs test/v14.2-runtime.test.mjs test/benchmark-confidence.test.mjs test/v14.3-intelligence.test.mjs",
|
|
42
|
+
"integrity": "node scripts/check-source-integrity.mjs",
|
|
43
|
+
"runtime:exports": "node scripts/check-runtime-exports.mjs"
|
|
56
44
|
},
|
|
57
45
|
"keywords": [
|
|
58
|
-
"
|
|
46
|
+
"pi-package",
|
|
47
|
+
"pi-agent",
|
|
59
48
|
"agent-skills",
|
|
60
49
|
"coding-agent",
|
|
61
50
|
"developer-tools",
|
|
@@ -63,12 +52,10 @@
|
|
|
63
52
|
"code-review",
|
|
64
53
|
"debugging",
|
|
65
54
|
"verification",
|
|
66
|
-
"visual-testing",
|
|
67
|
-
"browser-automation",
|
|
68
55
|
"multimodal-agents"
|
|
69
56
|
],
|
|
70
57
|
"engines": {
|
|
71
|
-
"node": ">=
|
|
58
|
+
"node": ">=22.19"
|
|
72
59
|
},
|
|
73
60
|
"publishConfig": {
|
|
74
61
|
"access": "public"
|
|
@@ -81,5 +68,28 @@
|
|
|
81
68
|
"bugs": {
|
|
82
69
|
"url": "https://github.com/laivannha0202/opencode-agent-skill-/issues"
|
|
83
70
|
},
|
|
84
|
-
"license": "MIT"
|
|
71
|
+
"license": "MIT",
|
|
72
|
+
"pi": {
|
|
73
|
+
"extensions": [
|
|
74
|
+
"./pi/extensions/ues.ts"
|
|
75
|
+
],
|
|
76
|
+
"skills": [
|
|
77
|
+
"./global-config/skills"
|
|
78
|
+
],
|
|
79
|
+
"prompts": [
|
|
80
|
+
"./pi/prompts/*.md"
|
|
81
|
+
]
|
|
82
|
+
},
|
|
83
|
+
"peerDependencies": {
|
|
84
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
85
|
+
"typebox": "*"
|
|
86
|
+
},
|
|
87
|
+
"peerDependenciesMeta": {
|
|
88
|
+
"@earendil-works/pi-coding-agent": {
|
|
89
|
+
"optional": true
|
|
90
|
+
},
|
|
91
|
+
"typebox": {
|
|
92
|
+
"optional": true
|
|
93
|
+
}
|
|
94
|
+
}
|
|
85
95
|
}
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { Type } from "typebox";
|
|
3
|
+
import { readFile, stat } from "node:fs/promises";
|
|
4
|
+
import { compactReversibleOutput } from "../../lib/performance-fabric.mjs";
|
|
5
|
+
import { getEvidenceSelected } from "../../lib/evidence-store.mjs";
|
|
6
|
+
import { recordVerification } from "../../lib/verification-broker.mjs";
|
|
7
|
+
import { runtimeWorkspaceFingerprint } from "../../lib/workspace-fingerprint.mjs";
|
|
8
|
+
import { destructiveShellRisk } from "../../lib/safety.mjs";
|
|
9
|
+
import {
|
|
10
|
+
canonicalVerificationCommand,
|
|
11
|
+
looksLikeVerificationCommand,
|
|
12
|
+
} from "../../lib/verification-command.mjs";
|
|
13
|
+
import {
|
|
14
|
+
applyAnchoredFileEdits,
|
|
15
|
+
diagnoseCode,
|
|
16
|
+
probeCodeIntelligence,
|
|
17
|
+
readAnchoredCode,
|
|
18
|
+
searchCodeIntelligence,
|
|
19
|
+
} from "../../lib/code-intelligence/index.mjs";
|
|
20
|
+
import { ingestDocument } from "../../lib/document-ingestion.mjs";
|
|
21
|
+
import { compactContext, expandContext, searchContext } from "../../lib/reversible-context.mjs";
|
|
22
|
+
|
|
23
|
+
const toolExecutionState = new Map<string, {
|
|
24
|
+
startedAt: number;
|
|
25
|
+
workspaceBefore?: string;
|
|
26
|
+
reusableCandidate: boolean;
|
|
27
|
+
canonicalVerification?: { command: string; args: string[]; raw: string } | null;
|
|
28
|
+
}>();
|
|
29
|
+
|
|
30
|
+
function configuredLimit() {
|
|
31
|
+
const raw = Number(process.env.UES_CHILD_TOOL_OUTPUT_LIMIT || 24 * 1024);
|
|
32
|
+
if (!Number.isFinite(raw)) return 24 * 1024;
|
|
33
|
+
return Math.max(4 * 1024, Math.min(128 * 1024, Math.trunc(raw)));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function configuredVerificationTimeout() {
|
|
37
|
+
const raw = Number(process.env.UES_CHILD_VERIFICATION_TIMEOUT_SEC || 300);
|
|
38
|
+
if (!Number.isFinite(raw) || raw <= 0) return 300;
|
|
39
|
+
return Math.max(30, Math.min(1800, Math.trunc(raw)));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function configuredRawCaptureLimit() {
|
|
43
|
+
const raw = Number(process.env.UES_CHILD_RAW_CAPTURE_LIMIT || 32 * 1024 * 1024);
|
|
44
|
+
if (!Number.isFinite(raw) || raw <= 0) return 32 * 1024 * 1024;
|
|
45
|
+
return Math.max(1024 * 1024, Math.min(128 * 1024 * 1024, Math.trunc(raw)));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function shellExitCode(event: any, rawText: string) {
|
|
49
|
+
if (!event.isError) return 0;
|
|
50
|
+
const match = String(rawText || "").match(/Command exited with code\s+(\d+)/i);
|
|
51
|
+
if (match) return Number(match[1]);
|
|
52
|
+
if (/timed out|timeout/i.test(rawText)) return 124;
|
|
53
|
+
if (/aborted/i.test(rawText)) return 130;
|
|
54
|
+
return 1;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function visibleText(event: any) {
|
|
58
|
+
return (event.content || [])
|
|
59
|
+
.filter((part: any) => part?.type === "text" && typeof part.text === "string")
|
|
60
|
+
.map((part: any) => part.text)
|
|
61
|
+
.join("\n");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function capturedText(event: any, fallback: string) {
|
|
65
|
+
const fullOutputPath = String((event.details as any)?.fullOutputPath || "").trim();
|
|
66
|
+
if (!fullOutputPath) return { text: fallback, full: false, sourcePath: null };
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const info = await stat(fullOutputPath);
|
|
70
|
+
if (!info.isFile() || info.size <= 0 || info.size > configuredRawCaptureLimit()) {
|
|
71
|
+
return { text: fallback, full: false, sourcePath: fullOutputPath };
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
text: await readFile(fullOutputPath, "utf8"),
|
|
75
|
+
full: true,
|
|
76
|
+
sourcePath: fullOutputPath,
|
|
77
|
+
};
|
|
78
|
+
} catch {
|
|
79
|
+
return { text: fallback, full: false, sourcePath: fullOutputPath };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export default function (pi: ExtensionAPI) {
|
|
84
|
+
const clearExecutionState = () => toolExecutionState.clear();
|
|
85
|
+
pi.on("session_start", clearExecutionState);
|
|
86
|
+
pi.on("session_shutdown", clearExecutionState);
|
|
87
|
+
|
|
88
|
+
pi.on("tool_call", async (event, ctx) => {
|
|
89
|
+
const toolName = String(event.toolName || "");
|
|
90
|
+
if (!["bash", "powershell"].includes(toolName)) return undefined;
|
|
91
|
+
|
|
92
|
+
const command = String((event.input as any)?.command || "");
|
|
93
|
+
const risk = destructiveShellRisk(command);
|
|
94
|
+
if (risk.risky) {
|
|
95
|
+
toolExecutionState.delete(String(event.toolCallId || ""));
|
|
96
|
+
return {
|
|
97
|
+
block: true,
|
|
98
|
+
reason:
|
|
99
|
+
`UES child safety blocked ${risk.id || "destructive"} shell operation` +
|
|
100
|
+
(risk.segment ? `: ${risk.segment}` : ""),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const canonicalVerification = canonicalVerificationCommand(command);
|
|
105
|
+
const reusableCandidate = Boolean(canonicalVerification);
|
|
106
|
+
const workspaceBefore = reusableCandidate
|
|
107
|
+
? (() => {
|
|
108
|
+
try { return runtimeWorkspaceFingerprint(ctx.cwd); } catch { return undefined; }
|
|
109
|
+
})()
|
|
110
|
+
: undefined;
|
|
111
|
+
toolExecutionState.set(String(event.toolCallId || ""), {
|
|
112
|
+
startedAt: Date.now(),
|
|
113
|
+
workspaceBefore,
|
|
114
|
+
reusableCandidate,
|
|
115
|
+
canonicalVerification,
|
|
116
|
+
});
|
|
117
|
+
if (looksLikeVerificationCommand(command) && (event.input as any)?.timeout == null) {
|
|
118
|
+
(event.input as any).timeout = configuredVerificationTimeout();
|
|
119
|
+
}
|
|
120
|
+
return undefined;
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
pi.on("tool_result", async (event, ctx) => {
|
|
124
|
+
const toolName = String(event.toolName || "");
|
|
125
|
+
if (!["bash", "powershell", "grep", "find", "ls"].includes(toolName)) {
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const shownText = visibleText(event);
|
|
130
|
+
const capture = await capturedText(event, shownText);
|
|
131
|
+
const rawText = capture.text;
|
|
132
|
+
const images = (event.content || []).filter((part: any) => part?.type !== "text");
|
|
133
|
+
const commandHint = String(
|
|
134
|
+
(event.input as any)?.command ||
|
|
135
|
+
(event.input as any)?.pattern ||
|
|
136
|
+
toolName ||
|
|
137
|
+
"tool",
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
const executionState = toolExecutionState.get(String(event.toolCallId || ""));
|
|
141
|
+
if (
|
|
142
|
+
["bash", "powershell"].includes(toolName) &&
|
|
143
|
+
executionState?.reusableCandidate === true &&
|
|
144
|
+
executionState.workspaceBefore &&
|
|
145
|
+
!event.isError
|
|
146
|
+
) {
|
|
147
|
+
const finishedAtMs = Date.now();
|
|
148
|
+
let workspaceAfter: string | undefined;
|
|
149
|
+
try { workspaceAfter = runtimeWorkspaceFingerprint(ctx.cwd); } catch {}
|
|
150
|
+
if (workspaceAfter && workspaceAfter === executionState.workspaceBefore) {
|
|
151
|
+
const canonical = executionState.canonicalVerification;
|
|
152
|
+
if (canonical) {
|
|
153
|
+
await recordVerification(ctx.cwd, {
|
|
154
|
+
command: canonical.command,
|
|
155
|
+
args: canonical.args,
|
|
156
|
+
exitCode: shellExitCode(event, shownText || rawText),
|
|
157
|
+
stdout: rawText,
|
|
158
|
+
stderr: "",
|
|
159
|
+
startedAt: new Date(executionState.startedAt).toISOString(),
|
|
160
|
+
finishedAt: new Date(finishedAtMs).toISOString(),
|
|
161
|
+
durationMs: Math.max(0, finishedAtMs - executionState.startedAt),
|
|
162
|
+
workspaceBefore: executionState.workspaceBefore,
|
|
163
|
+
workspaceAfter,
|
|
164
|
+
}).catch(() => null);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
toolExecutionState.delete(String(event.toolCallId || ""));
|
|
169
|
+
|
|
170
|
+
if (String(process.env.UES_CHILD_TOOL_COMPACTION || "") !== "1") return undefined;
|
|
171
|
+
const maxChars = configuredLimit();
|
|
172
|
+
if (!rawText || rawText.length <= maxChars) return undefined;
|
|
173
|
+
|
|
174
|
+
const compacted = await compactReversibleOutput(ctx.cwd, rawText, {
|
|
175
|
+
maxChars,
|
|
176
|
+
kind: `child-${toolName}-output`,
|
|
177
|
+
source: commandHint,
|
|
178
|
+
summary: capture.full
|
|
179
|
+
? `Full Pi shell output captured from ${capture.sourcePath} before model-visible compaction`
|
|
180
|
+
: "Captured Pi tool output preserved before model-visible compaction",
|
|
181
|
+
}).catch(() => null);
|
|
182
|
+
if (!compacted?.compacted) return undefined;
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
content: [{ type: "text", text: compacted.text }, ...images],
|
|
186
|
+
details: {
|
|
187
|
+
...(event.details && typeof event.details === "object" ? event.details : {}),
|
|
188
|
+
uesCompaction: {
|
|
189
|
+
strategy: compacted.strategy,
|
|
190
|
+
originalChars: compacted.originalChars,
|
|
191
|
+
returnedChars: compacted.returnedChars,
|
|
192
|
+
evidenceRef: compacted.evidenceRef,
|
|
193
|
+
rawCapture: capture.full ? "full-output-path" : "tool-result",
|
|
194
|
+
recoveryTool: "ues_evidence_get",
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
isError: event.isError,
|
|
198
|
+
usage: event.usage,
|
|
199
|
+
};
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const AnchoredEdit = Type.Object({
|
|
203
|
+
anchor: Type.String({ minLength: 1 }),
|
|
204
|
+
endAnchor: Type.Optional(Type.String({ minLength: 1 })),
|
|
205
|
+
replacement: Type.String(),
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
pi.registerTool({
|
|
209
|
+
name: "ues_code",
|
|
210
|
+
label: "UES Code Intelligence",
|
|
211
|
+
description:
|
|
212
|
+
"Bounded code/document/context intelligence for weak models: semantic/AST search, hash-anchored reads, optional LSP diagnostics, optional MarkItDown ingestion, and reversible context recovery.",
|
|
213
|
+
parameters: Type.Object({
|
|
214
|
+
action: Type.Union([
|
|
215
|
+
Type.Literal("status"),
|
|
216
|
+
Type.Literal("search"),
|
|
217
|
+
Type.Literal("read"),
|
|
218
|
+
Type.Literal("diagnostics"),
|
|
219
|
+
Type.Literal("document"),
|
|
220
|
+
Type.Literal("context-expand"),
|
|
221
|
+
Type.Literal("context-search"),
|
|
222
|
+
]),
|
|
223
|
+
file: Type.Optional(Type.String()),
|
|
224
|
+
query: Type.Optional(Type.String()),
|
|
225
|
+
structuralPattern: Type.Optional(Type.String()),
|
|
226
|
+
language: Type.Optional(Type.String()),
|
|
227
|
+
startLine: Type.Optional(Type.Number({ minimum: 1 })),
|
|
228
|
+
endLine: Type.Optional(Type.Number({ minimum: 1 })),
|
|
229
|
+
ref: Type.Optional(Type.String()),
|
|
230
|
+
maxBytes: Type.Optional(Type.Number({ minimum: 1, maximum: 128000 })),
|
|
231
|
+
}),
|
|
232
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
233
|
+
try {
|
|
234
|
+
let result: any;
|
|
235
|
+
if (params.action === "status") {
|
|
236
|
+
result = probeCodeIntelligence(params.file || "");
|
|
237
|
+
} else if (params.action === "search") {
|
|
238
|
+
if (!params.query) throw new Error("ues_code search requires query");
|
|
239
|
+
result = await searchCodeIntelligence(ctx.cwd, params.query, {
|
|
240
|
+
structuralPattern: params.structuralPattern,
|
|
241
|
+
language: params.language,
|
|
242
|
+
file: params.file,
|
|
243
|
+
maxResults: 12,
|
|
244
|
+
});
|
|
245
|
+
} else if (params.action === "read") {
|
|
246
|
+
if (!params.file) throw new Error("ues_code read requires file");
|
|
247
|
+
const startLine = Math.max(1, Math.trunc(Number(params.startLine || 1)));
|
|
248
|
+
const endLine = Math.max(startLine, Math.min(startLine + 399, Math.trunc(Number(params.endLine || startLine + 199))));
|
|
249
|
+
result = await readAnchoredCode(ctx.cwd, params.file, { startLine, endLine });
|
|
250
|
+
return {
|
|
251
|
+
content: [{ type: "text", text: [
|
|
252
|
+
`file: ${result.file}; lines: ${result.startLine}-${result.endLine}/${result.lineCount}; sourceHash: ${result.sourceHash}`,
|
|
253
|
+
"",
|
|
254
|
+
result.text,
|
|
255
|
+
].join("\n") }],
|
|
256
|
+
details: { action: params.action, file: result.file, sourceHash: result.sourceHash, startLine: result.startLine, endLine: result.endLine },
|
|
257
|
+
};
|
|
258
|
+
} else if (params.action === "diagnostics") {
|
|
259
|
+
if (!params.file) throw new Error("ues_code diagnostics requires file");
|
|
260
|
+
result = await diagnoseCode(ctx.cwd, params.file, { timeoutMs: 3000, maxDiagnostics: 40 });
|
|
261
|
+
} else if (params.action === "document") {
|
|
262
|
+
if (!params.file) throw new Error("ues_code document requires file");
|
|
263
|
+
const document = await ingestDocument(ctx.cwd, params.file, { maxBytes: Math.min(Number(params.maxBytes || 4 * 1024 * 1024), 4 * 1024 * 1024) });
|
|
264
|
+
const block = await compactContext(ctx.cwd, document.markdown, {
|
|
265
|
+
kind: "document-ingestion",
|
|
266
|
+
source: document.file,
|
|
267
|
+
summary: `Normalized document from ${document.provider}`,
|
|
268
|
+
});
|
|
269
|
+
result = {
|
|
270
|
+
provider: document.provider,
|
|
271
|
+
file: document.file,
|
|
272
|
+
bytes: document.bytes,
|
|
273
|
+
optionalDependency: document.optionalDependency,
|
|
274
|
+
contextRef: block.ref,
|
|
275
|
+
originalChars: block.originalChars,
|
|
276
|
+
summary: block.levels.T1,
|
|
277
|
+
};
|
|
278
|
+
} else if (params.action === "context-expand") {
|
|
279
|
+
if (!params.ref) throw new Error("ues_code context-expand requires ref");
|
|
280
|
+
const expanded = await expandContext(ctx.cwd, params.ref, { maxBytes: params.maxBytes || 16000 });
|
|
281
|
+
return {
|
|
282
|
+
content: [{ type: "text", text: expanded.content }],
|
|
283
|
+
details: { action: params.action, ref: expanded.ref, start: expanded.start, returnedBytes: expanded.returnedBytes, truncated: expanded.truncated },
|
|
284
|
+
};
|
|
285
|
+
} else if (params.action === "context-search") {
|
|
286
|
+
if (!params.ref || !params.query) throw new Error("ues_code context-search requires ref and query");
|
|
287
|
+
result = await searchContext(ctx.cwd, params.ref, params.query, { maxBytes: params.maxBytes || 512000, maxMatches: 12 });
|
|
288
|
+
} else {
|
|
289
|
+
throw new Error("unsupported ues_code action");
|
|
290
|
+
}
|
|
291
|
+
const encoded = JSON.stringify(result, null, 2);
|
|
292
|
+
return {
|
|
293
|
+
content: [{ type: "text", text: encoded.length <= 32000 ? encoded : encoded.slice(0, 32000) + "\n...[bounded by ues_code]" }],
|
|
294
|
+
details: { action: params.action, bounded: encoded.length > 32000 },
|
|
295
|
+
};
|
|
296
|
+
} catch (error) {
|
|
297
|
+
return {
|
|
298
|
+
content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
|
|
299
|
+
details: { action: params.action },
|
|
300
|
+
isError: true,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
pi.registerTool({
|
|
307
|
+
name: "ues_code_edit",
|
|
308
|
+
label: "UES Anchored Edit",
|
|
309
|
+
description:
|
|
310
|
+
"Apply fail-closed hash-anchored edits. A stale or mismatched anchor is rejected; re-read with ues_code instead of fuzzy retrying.",
|
|
311
|
+
parameters: Type.Object({
|
|
312
|
+
file: Type.String({ minLength: 1 }),
|
|
313
|
+
edits: Type.Array(AnchoredEdit, { minItems: 1, maxItems: 50 }),
|
|
314
|
+
dryRun: Type.Optional(Type.Boolean()),
|
|
315
|
+
diagnostics: Type.Optional(Type.Boolean()),
|
|
316
|
+
}),
|
|
317
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
318
|
+
try {
|
|
319
|
+
const edited = await applyAnchoredFileEdits(ctx.cwd, params.file, params.edits, { dryRun: params.dryRun === true });
|
|
320
|
+
const diagnostics = params.diagnostics === true && params.dryRun !== true
|
|
321
|
+
? await diagnoseCode(ctx.cwd, params.file, { timeoutMs: 3000, maxDiagnostics: 40 }).catch(() => null)
|
|
322
|
+
: null;
|
|
323
|
+
const result = {
|
|
324
|
+
file: edited.file,
|
|
325
|
+
applied: edited.applied,
|
|
326
|
+
dryRun: edited.dryRun,
|
|
327
|
+
sourceHash: edited.sourceHash,
|
|
328
|
+
outputHash: edited.outputHash,
|
|
329
|
+
diagnostics: diagnostics ? {
|
|
330
|
+
available: diagnostics.available,
|
|
331
|
+
provider: diagnostics.provider,
|
|
332
|
+
reason: diagnostics.reason,
|
|
333
|
+
count: diagnostics.diagnostics?.length || 0,
|
|
334
|
+
items: (diagnostics.diagnostics || []).slice(0, 40),
|
|
335
|
+
} : null,
|
|
336
|
+
};
|
|
337
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], details: result };
|
|
338
|
+
} catch (error) {
|
|
339
|
+
return {
|
|
340
|
+
content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
|
|
341
|
+
details: { file: params.file },
|
|
342
|
+
isError: true,
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
pi.registerTool({
|
|
349
|
+
name: "ues_evidence_get",
|
|
350
|
+
label: "UES Evidence Get",
|
|
351
|
+
description:
|
|
352
|
+
"Read an exact bounded slice or JSON selector from a UES Evidence Store reference when a compacted tool result says omitted raw evidence is available.",
|
|
353
|
+
parameters: Type.Object({
|
|
354
|
+
ref: Type.String({ minLength: 1 }),
|
|
355
|
+
start: Type.Optional(Type.Number({ minimum: 0 })),
|
|
356
|
+
maxBytes: Type.Optional(Type.Number({ minimum: 1, maximum: 64000 })),
|
|
357
|
+
}),
|
|
358
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
359
|
+
try {
|
|
360
|
+
const result = await getEvidenceSelected(ctx.cwd, params.ref, {
|
|
361
|
+
start: params.start || 0,
|
|
362
|
+
maxBytes: params.maxBytes || 16000,
|
|
363
|
+
});
|
|
364
|
+
return {
|
|
365
|
+
content: [{
|
|
366
|
+
type: "text",
|
|
367
|
+
text: [
|
|
368
|
+
`ref: ${result.ref}`,
|
|
369
|
+
`bytes: ${result.bytes}; start: ${result.start}; returned: ${result.returnedBytes}; truncated: ${result.truncated}`,
|
|
370
|
+
"",
|
|
371
|
+
result.content,
|
|
372
|
+
].join("\n"),
|
|
373
|
+
}],
|
|
374
|
+
details: {
|
|
375
|
+
ref: result.ref,
|
|
376
|
+
start: result.start,
|
|
377
|
+
returnedBytes: result.returnedBytes,
|
|
378
|
+
truncated: result.truncated,
|
|
379
|
+
},
|
|
380
|
+
};
|
|
381
|
+
} catch (error) {
|
|
382
|
+
return {
|
|
383
|
+
content: [{
|
|
384
|
+
type: "text",
|
|
385
|
+
text: error instanceof Error ? error.message : String(error),
|
|
386
|
+
}],
|
|
387
|
+
details: { ref: params.ref },
|
|
388
|
+
isError: true,
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
});
|
|
393
|
+
}
|