opencode-agent-skill 15.1.0 → 15.1.2

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.
Files changed (43) hide show
  1. package/README.md +5 -5
  2. package/docs/V15-MANAGED-RUNTIME.md +18 -0
  3. package/global-config/agents/verifier.md +6 -2
  4. package/lib/affected-tests.mjs +28 -7
  5. package/lib/capability-fabric.mjs +107 -48
  6. package/lib/code-intelligence/index.mjs +50 -24
  7. package/lib/code-intelligence/lsp-pool.mjs +831 -0
  8. package/lib/code-intelligence/lsp-provider.mjs +197 -20
  9. package/lib/compaction-resume-guard.mjs +76 -4
  10. package/lib/completion-auditor.mjs +20 -0
  11. package/lib/context-manifest.mjs +88 -36
  12. package/lib/decision-policy.mjs +40 -2
  13. package/lib/evidence-store.mjs +121 -31
  14. package/lib/executable-probe.mjs +69 -0
  15. package/lib/execution-contract.mjs +2 -2
  16. package/lib/hierarchical-context.mjs +31 -3
  17. package/lib/learning-engine.mjs +164 -65
  18. package/lib/memory-engine.mjs +177 -95
  19. package/lib/model-config.mjs +86 -7
  20. package/lib/performance-fabric.mjs +92 -0
  21. package/lib/permission-policy.mjs +232 -0
  22. package/lib/pi-rpc-pool.mjs +220 -24
  23. package/lib/provider-recovery.mjs +51 -0
  24. package/lib/repo-graph.mjs +40 -7
  25. package/lib/repo-inspect.mjs +3 -2
  26. package/lib/runtime-events.mjs +31 -10
  27. package/lib/semantic-index.mjs +69 -21
  28. package/lib/skill-compiler.mjs +84 -18
  29. package/lib/task-engine.mjs +28 -9
  30. package/lib/task-policy.mjs +80 -7
  31. package/lib/trajectory.mjs +25 -1
  32. package/lib/untrusted-output.mjs +106 -0
  33. package/lib/workspace-fingerprint.mjs +17 -9
  34. package/lib/workspace-hygiene.mjs +2 -2
  35. package/lib/worktree-sandbox.mjs +14 -8
  36. package/package.json +8 -6
  37. package/pi/extensions/ues-child-runtime.ts +116 -5
  38. package/pi/extensions/ues.ts +780 -81
  39. package/scripts/benchmark-lsp-pool.mjs +128 -0
  40. package/scripts/check-release-consistency.mjs +16 -4
  41. package/scripts/check-source-integrity.mjs +118 -6
  42. package/scripts/run-test-suite.mjs +143 -0
  43. 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,
@@ -18,6 +23,7 @@ import {
18
23
  probeCodeIntelligence,
19
24
  readAnchoredCode,
20
25
  searchCodeIntelligence,
26
+ shutdownLspPool,
21
27
  } from "../../lib/code-intelligence/index.mjs";
22
28
  import { ingestDocument } from "../../lib/document-ingestion.mjs";
23
29
  import { compactContext, expandContext, searchContext } from "../../lib/reversible-context.mjs";
@@ -32,6 +38,16 @@ import {
32
38
  waitForService,
33
39
  } from "../../lib/service-manager.mjs";
34
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
+
35
51
  const toolExecutionState = new Map<string, {
36
52
  startedAt: number;
37
53
  workspaceBefore?: string;
@@ -102,12 +118,45 @@ export default function (pi: ExtensionAPI) {
102
118
  pi.on("session_start", clearExecutionState);
103
119
  pi.on("session_shutdown", async (_event, ctx) => {
104
120
  clearExecutionState();
105
- await stopAllServices(ctx.cwd).catch(() => []);
121
+ await Promise.all([
122
+ stopAllServices(ctx.cwd).catch(() => []),
123
+ shutdownLspPool(ctx.cwd).catch(() => ({ stopped: 0, remaining: 0 })),
124
+ ]);
106
125
  });
107
126
 
108
127
  pi.on("tool_call", async (event, ctx) => {
109
128
  const toolName = String(event.toolName || "");
110
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
+ }
111
160
  const localEnvAllowed = String(process.env.UES_CHILD_ALLOW_LOCAL_ENV_WRITE || "") === "1";
112
161
  const writeTool = ["edit", "write", "write_file", "apply_patch", "ues_code_edit"].includes(toolName);
113
162
  const fileTool = ["read", "edit", "write", "write_file", "apply_patch", "ues_code", "ues_code_edit"].includes(toolName);
@@ -186,11 +235,37 @@ export default function (pi: ExtensionAPI) {
186
235
 
187
236
  pi.on("tool_result", async (event, ctx) => {
188
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
+
189
266
  if (!["bash", "powershell", "grep", "find", "ls"].includes(toolName)) {
190
267
  return undefined;
191
268
  }
192
-
193
- const shownText = visibleText(event);
194
269
  const capture = await capturedText(event, shownText);
195
270
  const rawText = capture.text;
196
271
  const images = (event.content || []).filter((part: any) => part?.type !== "text");
@@ -375,9 +450,45 @@ export default function (pi: ExtensionAPI) {
375
450
  throw new Error("unsupported ues_code action");
376
451
  }
377
452
  const encoded = JSON.stringify(result, null, 2);
453
+ const bounded = encoded.length > 32000;
454
+ let contextRef: string | null = null;
455
+ let visible = encoded;
456
+ if (bounded) {
457
+ const preserved = await compactContext(ctx.cwd, encoded, {
458
+ kind: "ues-code-result",
459
+ source: `ues_code:${params.action}`,
460
+ summary: `Full child code-intelligence result for ${params.action}; preserve exact JSON before model-visible bounding`,
461
+ }).catch(() => null);
462
+ contextRef = preserved?.ref || null;
463
+ const metadataFirst = {
464
+ schemaVersion: result?.schemaVersion || 1,
465
+ action: params.action,
466
+ file: result?.file || null,
467
+ available: result?.available ?? null,
468
+ provider: result?.provider || null,
469
+ operation: result?.operation || null,
470
+ reason: result?.reason || null,
471
+ persistent: result?.persistent ?? null,
472
+ pool: result?.pool || result?.lsp?.persistentPool || null,
473
+ bounded: true,
474
+ originalChars: encoded.length,
475
+ contextRef,
476
+ preview: encoded.slice(0, 22000),
477
+ };
478
+ visible = JSON.stringify(metadataFirst, null, 2) +
479
+ "\n...[full result preserved; use ues_code context-expand with contextRef when more evidence is needed]";
480
+ }
378
481
  return {
379
- content: [{ type: "text", text: encoded.length <= 32000 ? encoded : encoded.slice(0, 32000) + "\n...[bounded by ues_code]" }],
380
- details: { action: params.action, bounded: encoded.length > 32000 },
482
+ content: [{ type: "text", text: visible }],
483
+ details: {
484
+ action: params.action,
485
+ bounded,
486
+ originalChars: encoded.length,
487
+ contextRef,
488
+ provider: result?.provider || null,
489
+ persistent: result?.persistent ?? null,
490
+ pool: result?.pool || result?.lsp?.persistentPool || null,
491
+ },
381
492
  };
382
493
  } catch (error) {
383
494
  return {