opencode-agent-skill 15.0.0 → 15.1.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 +5 -5
- package/docs/V15-MANAGED-RUNTIME.md +18 -0
- package/global-config/agents/verifier.md +6 -2
- package/lib/affected-tests.mjs +58 -8
- package/lib/capability-fabric.mjs +107 -48
- package/lib/code-intelligence/index.mjs +4 -15
- package/lib/code-intelligence/lsp-pool.mjs +694 -0
- package/lib/code-intelligence/lsp-provider.mjs +481 -67
- package/lib/compaction-resume-guard.mjs +327 -0
- package/lib/completion-auditor.mjs +20 -0
- package/lib/context-engine-v11.mjs +20 -7
- package/lib/context-manifest.mjs +38 -21
- package/lib/decision-policy.mjs +40 -2
- package/lib/evidence-store.mjs +121 -31
- package/lib/executable-probe.mjs +69 -0
- package/lib/execution-contract.mjs +29 -16
- package/lib/hierarchical-context.mjs +31 -3
- package/lib/learning-engine.mjs +164 -65
- package/lib/memory-engine.mjs +348 -98
- package/lib/model-config.mjs +86 -7
- package/lib/performance-fabric.mjs +354 -107
- package/lib/permission-policy.mjs +232 -0
- package/lib/pi-rpc-pool.mjs +170 -5
- package/lib/provider-recovery.mjs +51 -0
- package/lib/repo-graph.mjs +38 -5
- package/lib/runtime-events.mjs +31 -10
- package/lib/semantic-index.mjs +67 -20
- package/lib/skill-compiler.mjs +84 -18
- package/lib/subagent-artifacts.mjs +182 -0
- package/lib/task-policy.mjs +80 -7
- package/lib/trajectory.mjs +25 -1
- package/lib/untrusted-output.mjs +106 -0
- package/lib/verification-broker.mjs +32 -27
- package/lib/workspace-fingerprint.mjs +43 -8
- package/lib/workspace-hygiene.mjs +481 -0
- package/package.json +8 -6
- package/pi/extensions/ues-child-runtime.ts +103 -5
- package/pi/extensions/ues.ts +984 -95
- package/scripts/benchmark-lsp-pool.mjs +128 -0
- package/scripts/check-release-consistency.mjs +16 -4
- package/scripts/check-source-integrity.mjs +60 -1
- package/scripts/run-test-suite.mjs +143 -0
- package/scripts/smoke-package-closure.mjs +4 -0
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { Type } from "typebox";
|
|
3
3
|
import { readFile, stat } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
4
5
|
import { compactReversibleOutput } from "../../lib/performance-fabric.mjs";
|
|
5
6
|
import { getEvidenceSelected } from "../../lib/evidence-store.mjs";
|
|
6
7
|
import { recordVerification } from "../../lib/verification-broker.mjs";
|
|
7
8
|
import { runtimeWorkspaceFingerprint } from "../../lib/workspace-fingerprint.mjs";
|
|
8
9
|
import { destructiveShellRisk } from "../../lib/safety.mjs";
|
|
10
|
+
import { getUesConfigDir } from "../../lib/runtime-config.mjs";
|
|
11
|
+
import { PermissionPolicyStore, permissionRecoveryHint, toolPermissionRequest } from "../../lib/permission-policy.mjs";
|
|
12
|
+
import { analyzeUntrustedOutput, renderUntrustedOutputWarning } from "../../lib/untrusted-output.mjs";
|
|
13
|
+
import { mcpExecutionPolicy } from "../../lib/mcp-tool-policy.mjs";
|
|
9
14
|
import { crossToolTempPathRisk, isLocalEnvPath, localEnvWriteRisk } from "../../lib/execution-contract.mjs";
|
|
10
15
|
import {
|
|
11
16
|
canonicalVerificationCommand,
|
|
@@ -14,9 +19,11 @@ import {
|
|
|
14
19
|
import {
|
|
15
20
|
applyAnchoredFileEdits,
|
|
16
21
|
diagnoseCode,
|
|
22
|
+
lspOperation,
|
|
17
23
|
probeCodeIntelligence,
|
|
18
24
|
readAnchoredCode,
|
|
19
25
|
searchCodeIntelligence,
|
|
26
|
+
shutdownLspPool,
|
|
20
27
|
} from "../../lib/code-intelligence/index.mjs";
|
|
21
28
|
import { ingestDocument } from "../../lib/document-ingestion.mjs";
|
|
22
29
|
import { compactContext, expandContext, searchContext } from "../../lib/reversible-context.mjs";
|
|
@@ -31,6 +38,16 @@ import {
|
|
|
31
38
|
waitForService,
|
|
32
39
|
} from "../../lib/service-manager.mjs";
|
|
33
40
|
|
|
41
|
+
const PERMISSION_POLICY = new PermissionPolicyStore(
|
|
42
|
+
path.join(getUesConfigDir(), ".ues", "permissions.json"),
|
|
43
|
+
);
|
|
44
|
+
const EXTERNAL_TOOL_NAMES = new Set(
|
|
45
|
+
String(process.env.UES_CHILD_EXTERNAL_TOOL_NAMES || "")
|
|
46
|
+
.split(",")
|
|
47
|
+
.map((value) => value.trim())
|
|
48
|
+
.filter(Boolean),
|
|
49
|
+
);
|
|
50
|
+
|
|
34
51
|
const toolExecutionState = new Map<string, {
|
|
35
52
|
startedAt: number;
|
|
36
53
|
workspaceBefore?: string;
|
|
@@ -101,12 +118,45 @@ export default function (pi: ExtensionAPI) {
|
|
|
101
118
|
pi.on("session_start", clearExecutionState);
|
|
102
119
|
pi.on("session_shutdown", async (_event, ctx) => {
|
|
103
120
|
clearExecutionState();
|
|
104
|
-
await
|
|
121
|
+
await Promise.all([
|
|
122
|
+
stopAllServices(ctx.cwd).catch(() => []),
|
|
123
|
+
shutdownLspPool(ctx.cwd).catch(() => ({ stopped: 0, remaining: 0 })),
|
|
124
|
+
]);
|
|
105
125
|
});
|
|
106
126
|
|
|
107
127
|
pi.on("tool_call", async (event, ctx) => {
|
|
108
128
|
const toolName = String(event.toolName || "");
|
|
109
129
|
const input: any = event.input || {};
|
|
130
|
+
const permissionRequest = toolPermissionRequest(toolName, input);
|
|
131
|
+
const configuredPermission: any = await PERMISSION_POLICY.evaluate(
|
|
132
|
+
permissionRequest,
|
|
133
|
+
{ agent: String(process.env.UES_CHILD_AGENT || "ues-child") },
|
|
134
|
+
).catch((error) => ({
|
|
135
|
+
configured: true,
|
|
136
|
+
decision: null,
|
|
137
|
+
error: error instanceof Error ? error.message : String(error),
|
|
138
|
+
}));
|
|
139
|
+
if (configuredPermission.error) {
|
|
140
|
+
toolExecutionState.delete(String(event.toolCallId || ""));
|
|
141
|
+
return {
|
|
142
|
+
block: true,
|
|
143
|
+
reason: "UES permission policy is invalid: " + configuredPermission.error,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
if (configuredPermission?.decision?.effect === "deny") {
|
|
147
|
+
toolExecutionState.delete(String(event.toolCallId || ""));
|
|
148
|
+
return {
|
|
149
|
+
block: true,
|
|
150
|
+
reason: permissionRecoveryHint(permissionRequest, configuredPermission.decision, { effect: "deny" }),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
if (configuredPermission?.decision?.effect === "ask") {
|
|
154
|
+
toolExecutionState.delete(String(event.toolCallId || ""));
|
|
155
|
+
return {
|
|
156
|
+
block: true,
|
|
157
|
+
reason: permissionRecoveryHint(permissionRequest, configuredPermission.decision, { effect: "ask" }),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
110
160
|
const localEnvAllowed = String(process.env.UES_CHILD_ALLOW_LOCAL_ENV_WRITE || "") === "1";
|
|
111
161
|
const writeTool = ["edit", "write", "write_file", "apply_patch", "ues_code_edit"].includes(toolName);
|
|
112
162
|
const fileTool = ["read", "edit", "write", "write_file", "apply_patch", "ues_code", "ues_code_edit"].includes(toolName);
|
|
@@ -185,11 +235,37 @@ export default function (pi: ExtensionAPI) {
|
|
|
185
235
|
|
|
186
236
|
pi.on("tool_result", async (event, ctx) => {
|
|
187
237
|
const toolName = String(event.toolName || "");
|
|
238
|
+
const shownText = visibleText(event);
|
|
239
|
+
const allTools = typeof (pi as any).getAllTools === "function" ? (pi as any).getAllTools() : [];
|
|
240
|
+
const descriptor = allTools.find((tool: any) => String(tool?.name || "") === toolName);
|
|
241
|
+
const externalPolicy = mcpExecutionPolicy(descriptor || { name: toolName });
|
|
242
|
+
const externalBoundary =
|
|
243
|
+
EXTERNAL_TOOL_NAMES.has(toolName) ||
|
|
244
|
+
externalPolicy.externalEvidenceBoundary === true;
|
|
245
|
+
if (externalBoundary && shownText) {
|
|
246
|
+
const analysis = analyzeUntrustedOutput(shownText, { source: toolName });
|
|
247
|
+
if (analysis.flagged) {
|
|
248
|
+
const originalContent = Array.isArray(event.content)
|
|
249
|
+
? event.content
|
|
250
|
+
: [{ type: "text", text: shownText }];
|
|
251
|
+
return {
|
|
252
|
+
content: [
|
|
253
|
+
{ type: "text", text: renderUntrustedOutputWarning(analysis, { source: toolName }) },
|
|
254
|
+
...originalContent,
|
|
255
|
+
],
|
|
256
|
+
details: {
|
|
257
|
+
...(event.details && typeof event.details === "object" ? event.details : {}),
|
|
258
|
+
uesUntrustedOutputBoundary: analysis,
|
|
259
|
+
},
|
|
260
|
+
isError: event.isError,
|
|
261
|
+
usage: event.usage,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
188
266
|
if (!["bash", "powershell", "grep", "find", "ls"].includes(toolName)) {
|
|
189
267
|
return undefined;
|
|
190
268
|
}
|
|
191
|
-
|
|
192
|
-
const shownText = visibleText(event);
|
|
193
269
|
const capture = await capturedText(event, shownText);
|
|
194
270
|
const rawText = capture.text;
|
|
195
271
|
const images = (event.content || []).filter((part: any) => part?.type !== "text");
|
|
@@ -272,13 +348,20 @@ export default function (pi: ExtensionAPI) {
|
|
|
272
348
|
name: "ues_code",
|
|
273
349
|
label: "UES Code Intelligence",
|
|
274
350
|
description:
|
|
275
|
-
"Bounded code/document/context intelligence for weak models: semantic/AST search, hash-anchored reads,
|
|
351
|
+
"Bounded code/document/context intelligence for weak models: semantic/AST search, hash-anchored reads, deterministic LSP definition/references/symbols/hover/rename-preview/call hierarchy, diagnostics, optional MarkItDown ingestion, and reversible context recovery.",
|
|
276
352
|
parameters: Type.Object({
|
|
277
353
|
action: Type.Union([
|
|
278
354
|
Type.Literal("status"),
|
|
279
355
|
Type.Literal("search"),
|
|
280
356
|
Type.Literal("read"),
|
|
281
357
|
Type.Literal("diagnostics"),
|
|
358
|
+
Type.Literal("definition"),
|
|
359
|
+
Type.Literal("references"),
|
|
360
|
+
Type.Literal("symbols"),
|
|
361
|
+
Type.Literal("hover"),
|
|
362
|
+
Type.Literal("rename-preview"),
|
|
363
|
+
Type.Literal("incoming-calls"),
|
|
364
|
+
Type.Literal("outgoing-calls"),
|
|
282
365
|
Type.Literal("document"),
|
|
283
366
|
Type.Literal("context-expand"),
|
|
284
367
|
Type.Literal("context-search"),
|
|
@@ -289,6 +372,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
289
372
|
language: Type.Optional(Type.String()),
|
|
290
373
|
startLine: Type.Optional(Type.Number({ minimum: 1 })),
|
|
291
374
|
endLine: Type.Optional(Type.Number({ minimum: 1 })),
|
|
375
|
+
line: Type.Optional(Type.Number({ minimum: 1, description: "1-based source line for LSP operations" })),
|
|
376
|
+
character: Type.Optional(Type.Number({ minimum: 1, description: "1-based source character for LSP operations" })),
|
|
377
|
+
newName: Type.Optional(Type.String({ minLength: 1, maxLength: 512 })),
|
|
378
|
+
includeDeclaration: Type.Optional(Type.Boolean()),
|
|
292
379
|
ref: Type.Optional(Type.String()),
|
|
293
380
|
maxBytes: Type.Optional(Type.Number({ minimum: 1, maximum: 128000 })),
|
|
294
381
|
}),
|
|
@@ -320,7 +407,18 @@ export default function (pi: ExtensionAPI) {
|
|
|
320
407
|
};
|
|
321
408
|
} else if (params.action === "diagnostics") {
|
|
322
409
|
if (!params.file) throw new Error("ues_code diagnostics requires file");
|
|
323
|
-
result = await diagnoseCode(ctx.cwd, params.file, { timeoutMs:
|
|
410
|
+
result = await diagnoseCode(ctx.cwd, params.file, { timeoutMs: 5000, maxResults: 80 });
|
|
411
|
+
} else if (["definition", "references", "symbols", "hover", "rename-preview", "incoming-calls", "outgoing-calls"].includes(params.action)) {
|
|
412
|
+
if (!params.file) throw new Error(`ues_code ${params.action} requires file`);
|
|
413
|
+
if (params.action === "rename-preview" && !params.newName) throw new Error("ues_code rename-preview requires newName");
|
|
414
|
+
result = await lspOperation(ctx.cwd, params.file, params.action, {
|
|
415
|
+
line: params.line || 1,
|
|
416
|
+
character: params.character || 1,
|
|
417
|
+
newName: params.newName,
|
|
418
|
+
includeDeclaration: params.includeDeclaration,
|
|
419
|
+
timeoutMs: 7000,
|
|
420
|
+
maxResults: 120,
|
|
421
|
+
});
|
|
324
422
|
} else if (params.action === "document") {
|
|
325
423
|
if (!params.file) throw new Error("ues_code document requires file");
|
|
326
424
|
const document = await ingestDocument(ctx.cwd, params.file, { maxBytes: Math.min(Number(params.maxBytes || 4 * 1024 * 1024), 4 * 1024 * 1024) });
|