@pi-archimedes/sudo 2.10.4 → 2.11.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-archimedes/sudo",
3
- "version": "2.10.4",
3
+ "version": "2.11.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/danielcherubini/pi-archimedes.git"
@@ -19,16 +19,16 @@
19
19
  "./guard": "./src/guard.ts"
20
20
  },
21
21
  "dependencies": {
22
- "@pi-archimedes/core": "2.10.4"
22
+ "@pi-archimedes/core": "2.11.1"
23
23
  },
24
24
  "peerDependencies": {
25
- "@earendil-works/pi-coding-agent": ">=0.1.0",
26
- "@earendil-works/pi-tui": ">=0.1.0",
25
+ "@earendil-works/pi-coding-agent": ">=0.99.0",
26
+ "@earendil-works/pi-tui": ">=0.99.0",
27
27
  "typebox": ">=1.1.0"
28
28
  },
29
29
  "devDependencies": {
30
- "@earendil-works/pi-coding-agent": "^0.87.0",
31
- "@earendil-works/pi-tui": "^0.87.0",
30
+ "@earendil-works/pi-coding-agent": "1.2.0",
31
+ "@earendil-works/pi-tui": "1.2.0",
32
32
  "typebox": "^1.1.38",
33
33
  "typescript": "^6.0.0"
34
34
  },
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Task 11 item 3 — what pi's callers are told about `sudo_exec`.
3
+ *
4
+ * `annotations` are author-declared hints with MCP's meaning, and pi documents
5
+ * them as unverified — the input for a permission gate that decides which calls
6
+ * to confirm, not a guarantee (`pi: dist/core/extensions/types.d.ts`,
7
+ * `ToolAnnotations`). So this test pins the declaration, nothing more: `sudo_exec`
8
+ * runs arbitrary privileged commands, so it is destructive and not read-only.
9
+ */
10
+
11
+ import { describe, it, expect } from "vitest";
12
+ import { createSudoExecTool } from "./tool.js";
13
+
14
+ const tool = createSudoExecTool() as unknown as {
15
+ name: string;
16
+ annotations?: { readOnlyHint?: boolean; destructiveHint?: boolean; idempotentHint?: boolean; openWorldHint?: boolean };
17
+ exposure?: string;
18
+ };
19
+
20
+ describe("sudo_exec annotations", () => {
21
+ it("says it is destructive", () => {
22
+ expect(tool.annotations?.destructiveHint).toBe(true);
23
+ });
24
+
25
+ it("says it is not read-only", () => {
26
+ expect(tool.annotations?.readOnlyHint).toBe(false);
27
+ });
28
+
29
+ it("leaves the hints it has not earned undeclared", () => {
30
+ // idempotentHint would be a lie — a second `sudo rm` is not a no-op — and
31
+ // openWorldHint belongs to the tools that reach the web, not this one.
32
+ expect(tool.annotations?.idempotentHint).toBeUndefined();
33
+ expect(tool.annotations?.openWorldHint).toBeUndefined();
34
+ });
35
+
36
+ it("stays reachable by default (direct exposure, active on registration)", () => {
37
+ expect(tool.exposure ?? "direct").toBe("direct");
38
+ });
39
+ });
package/src/tool.ts CHANGED
@@ -385,6 +385,16 @@ export function createSudoExecTool(options: {
385
385
  label: "sudo",
386
386
  description: SUDO_EXEC_DESCRIPTION,
387
387
  parameters: SudoExecParamsSchema,
388
+ /**
389
+ * Author-declared hints with MCP's meaning, which pi passes to whatever a
390
+ * permission extension does with them and documents as unverified
391
+ * (`pi: dist/core/extensions/types.d.ts`, `ToolAnnotations`). This one is
392
+ * worth declaring: the tool runs an arbitrary command as root, so it may
393
+ * overwrite or delete rather than only add, and it is not read-only. The
394
+ * confirmation this package does in its own handler is unchanged — a hint
395
+ * is not a gate.
396
+ */
397
+ annotations: { destructiveHint: true, readOnlyHint: false },
388
398
 
389
399
  // NOTE: no return-type annotation on execute — pi reads `isError` at
390
400
  // runtime though AgentToolResult omits it; the inferred union escapes