@gotgenes/pi-permission-system 7.1.3 → 7.2.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/CHANGELOG.md +14 -0
- package/package.json +7 -3
- package/src/active-agent.ts +1 -1
- package/src/bash-arity.ts +1 -0
- package/src/config-modal.ts +2 -0
- package/src/forwarded-permissions/io.ts +4 -2
- package/src/forwarded-permissions/polling.ts +8 -7
- package/src/handlers/before-agent-start.ts +7 -6
- package/src/handlers/gates/bash-external-directory.ts +4 -4
- package/src/handlers/gates/bash-path-extractor.ts +4 -6
- package/src/handlers/gates/bash-path.ts +5 -5
- package/src/handlers/gates/descriptor.ts +6 -6
- package/src/handlers/gates/external-directory.ts +2 -2
- package/src/handlers/gates/helpers.ts +2 -2
- package/src/handlers/gates/path.ts +4 -4
- package/src/handlers/gates/runner.ts +7 -4
- package/src/handlers/gates/skill-read.ts +5 -5
- package/src/handlers/gates/tool.ts +5 -5
- package/src/handlers/lifecycle.ts +9 -8
- package/src/handlers/permission-gate-handler.ts +12 -7
- package/src/logging.ts +3 -0
- package/src/node-modules-discovery.ts +1 -1
- package/src/normalize.ts +1 -0
- package/src/permission-event-rpc.ts +2 -0
- package/src/permission-manager.ts +7 -6
- package/src/permission-merge.ts +4 -2
- package/src/permission-prompter.ts +3 -0
- package/src/permission-prompts.ts +1 -1
- package/src/policy-loader.ts +5 -5
- package/src/service.ts +1 -0
- package/src/skill-prompt-sanitizer.ts +3 -3
- package/src/tool-registry.ts +1 -1
- package/src/wildcard-matcher.ts +2 -2
- package/src/yolo-mode.ts +2 -1
- package/{tests → test}/active-agent.test.ts +1 -1
- package/{tests → test}/bash-arity.test.ts +4 -4
- package/{tests → test}/bash-external-directory.test.ts +3 -3
- package/{tests → test}/common.test.ts +1 -1
- package/{tests → test}/config-loader.test.ts +1 -1
- package/{tests → test}/config-modal.test.ts +9 -11
- package/{tests → test}/config-paths.test.ts +1 -1
- package/{tests → test}/config-reporter.test.ts +4 -4
- package/{tests → test}/denial-messages.test.ts +2 -2
- package/{tests → test}/expand-home.test.ts +1 -1
- package/{tests → test}/extension-config.test.ts +1 -1
- package/{tests → test}/extension-paths.test.ts +2 -2
- package/{tests → test}/forwarded-permissions/io.test.ts +2 -2
- package/{tests → test}/forwarding-manager.test.ts +1 -1
- package/{tests → test}/handlers/before-agent-start.test.ts +5 -5
- package/{tests → test}/handlers/external-directory-integration.test.ts +8 -8
- package/{tests → test}/handlers/external-directory-session-dedup.test.ts +6 -6
- package/{tests → test}/handlers/gates/bash-external-directory.test.ts +5 -8
- package/{tests → test}/handlers/gates/bash-path.test.ts +6 -9
- package/{tests → test}/handlers/gates/external-directory-messages.test.ts +1 -1
- package/{tests → test}/handlers/gates/external-directory.test.ts +4 -7
- package/{tests → test}/handlers/gates/helpers.test.ts +1 -1
- package/{tests → test}/handlers/gates/path.test.ts +6 -6
- package/{tests → test}/handlers/gates/runner.test.ts +5 -5
- package/{tests → test}/handlers/gates/skill-read.test.ts +12 -14
- package/{tests → test}/handlers/gates/tool.test.ts +4 -4
- package/{tests → test}/handlers/input-events.test.ts +7 -7
- package/{tests → test}/handlers/input.test.ts +5 -5
- package/{tests → test}/handlers/lifecycle.test.ts +2 -2
- package/{tests → test}/handlers/tool-call-events.test.ts +7 -7
- package/{tests → test}/handlers/tool-call.test.ts +5 -5
- package/{tests → test}/input-normalizer.test.ts +2 -2
- package/{tests → test}/mcp-targets.test.ts +1 -1
- package/{tests → test}/node-modules-discovery.test.ts +1 -1
- package/{tests → test}/normalize.test.ts +1 -1
- package/{tests → test}/path-utils.test.ts +1 -1
- package/{tests → test}/pattern-suggest.test.ts +1 -1
- package/{tests → test}/permission-dialog.test.ts +1 -1
- package/{tests → test}/permission-event-rpc.test.ts +4 -3
- package/{tests → test}/permission-events.test.ts +6 -4
- package/{tests → test}/permission-forwarding.test.ts +2 -1
- package/{tests → test}/permission-gate.test.ts +2 -2
- package/{tests → test}/permission-manager-unified.test.ts +9 -7
- package/{tests → test}/permission-merge.test.ts +1 -1
- package/{tests → test}/permission-prompter.test.ts +4 -4
- package/{tests → test}/permission-prompts.test.ts +4 -4
- package/{tests → test}/permission-session.test.ts +9 -9
- package/{tests → test}/permission-system.test.ts +21 -21
- package/{tests → test}/pi-infrastructure-read.test.ts +2 -2
- package/{tests → test}/policy-loader.test.ts +1 -1
- package/{tests → test}/rule.test.ts +2 -2
- package/{tests → test}/runtime.test.ts +4 -4
- package/{tests → test}/service.test.ts +4 -4
- package/{tests → test}/session-logger.test.ts +2 -2
- package/{tests → test}/session-rules.test.ts +2 -2
- package/{tests → test}/session-start.test.ts +4 -4
- package/{tests → test}/skill-prompt-sanitizer.test.ts +3 -3
- package/{tests → test}/subagent-context.test.ts +2 -2
- package/{tests → test}/synthesize.test.ts +3 -3
- package/{tests → test}/system-prompt-sanitizer.test.ts +1 -1
- package/{tests → test}/tool-input-preview.test.ts +3 -3
- package/{tests → test}/tool-registry.test.ts +1 -1
- package/{tests → test}/wildcard-matcher.test.ts +1 -1
- package/{tests → test}/yolo-mode.test.ts +2 -2
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
|
|
3
|
-
import { describeToolGate } from "
|
|
4
|
-
import type { ToolCallContext } from "
|
|
5
|
-
import type { PermissionCheckResult } from "
|
|
3
|
+
import { describeToolGate } from "#src/handlers/gates/tool";
|
|
4
|
+
import type { ToolCallContext } from "#src/handlers/gates/types";
|
|
5
|
+
import type { PermissionCheckResult } from "#src/types";
|
|
6
6
|
|
|
7
7
|
// ── helpers ────────────────────────────────────────────────────────────────
|
|
8
8
|
|
|
@@ -93,7 +93,7 @@ describe("describeToolGate", () => {
|
|
|
93
93
|
it("populates denialContext with agent name when provided", () => {
|
|
94
94
|
const check = makeCheckResult("ask", { toolName: "read" });
|
|
95
95
|
const desc = describeToolGate(makeTcc({ agentName: "my-agent" }), check);
|
|
96
|
-
expect(desc.denialContext
|
|
96
|
+
expect(desc.denialContext.agentName).toBe("my-agent");
|
|
97
97
|
});
|
|
98
98
|
|
|
99
99
|
it("populates denialContext with input for tool context", () => {
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
5
5
|
import { describe, expect, it, vi } from "vitest";
|
|
6
6
|
|
|
7
|
-
import { PermissionGateHandler } from "
|
|
8
|
-
import type { PermissionDecisionEvent } from "
|
|
9
|
-
import { PERMISSIONS_DECISION_CHANNEL } from "
|
|
10
|
-
import type { PermissionSession } from "
|
|
11
|
-
import type { ToolRegistry } from "
|
|
12
|
-
import type { PermissionState } from "
|
|
7
|
+
import { PermissionGateHandler } from "#src/handlers/permission-gate-handler";
|
|
8
|
+
import type { PermissionDecisionEvent } from "#src/permission-events";
|
|
9
|
+
import { PERMISSIONS_DECISION_CHANNEL } from "#src/permission-events";
|
|
10
|
+
import type { PermissionSession } from "#src/permission-session";
|
|
11
|
+
import type { ToolRegistry } from "#src/tool-registry";
|
|
12
|
+
import type { PermissionState } from "#src/types";
|
|
13
13
|
|
|
14
14
|
// ── helpers ────────────────────────────────────────────────────────────────
|
|
15
15
|
|
|
@@ -54,7 +54,7 @@ function makeSession(
|
|
|
54
54
|
origin: "global",
|
|
55
55
|
matchedPattern: "*",
|
|
56
56
|
}),
|
|
57
|
-
getToolPermission: vi.fn().mockReturnValue("allow"
|
|
57
|
+
getToolPermission: vi.fn().mockReturnValue("allow"),
|
|
58
58
|
getSessionRuleset: vi.fn().mockReturnValue([]),
|
|
59
59
|
approveSessionRule: vi.fn(),
|
|
60
60
|
canPrompt: vi.fn().mockReturnValue(true),
|
|
@@ -4,10 +4,10 @@ import { describe, expect, it, vi } from "vitest";
|
|
|
4
4
|
import {
|
|
5
5
|
extractSkillNameFromInput,
|
|
6
6
|
PermissionGateHandler,
|
|
7
|
-
} from "
|
|
8
|
-
import type { PermissionSession } from "
|
|
9
|
-
import type { ToolRegistry } from "
|
|
10
|
-
import type { PermissionState } from "
|
|
7
|
+
} from "#src/handlers/permission-gate-handler";
|
|
8
|
+
import type { PermissionSession } from "#src/permission-session";
|
|
9
|
+
import type { ToolRegistry } from "#src/tool-registry";
|
|
10
|
+
import type { PermissionState } from "#src/types";
|
|
11
11
|
|
|
12
12
|
// ── helpers ────────────────────────────────────────────────────────────────
|
|
13
13
|
|
|
@@ -42,7 +42,7 @@ function makeSession(
|
|
|
42
42
|
activate: vi.fn(),
|
|
43
43
|
resolveAgentName: vi.fn().mockReturnValue(null),
|
|
44
44
|
checkPermission: vi.fn().mockReturnValue({ state: "allow" }),
|
|
45
|
-
getToolPermission: vi.fn().mockReturnValue("allow"
|
|
45
|
+
getToolPermission: vi.fn().mockReturnValue("allow"),
|
|
46
46
|
getSessionRuleset: vi.fn().mockReturnValue([]),
|
|
47
47
|
approveSessionRule: vi.fn(),
|
|
48
48
|
canPrompt: vi.fn().mockReturnValue(true),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { describe, expect, it, vi } from "vitest";
|
|
3
|
-
import { SessionLifecycleHandler } from "
|
|
4
|
-
import type { PermissionSession } from "
|
|
3
|
+
import { SessionLifecycleHandler } from "#src/handlers/lifecycle";
|
|
4
|
+
import type { PermissionSession } from "#src/permission-session";
|
|
5
5
|
|
|
6
6
|
// ── status stub ────────────────────────────────────────────────────────────
|
|
7
7
|
vi.mock("../../src/status", () => ({
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
6
6
|
import { describe, expect, it, vi } from "vitest";
|
|
7
7
|
|
|
8
|
-
import { PermissionGateHandler } from "
|
|
9
|
-
import type { PermissionDecisionEvent } from "
|
|
10
|
-
import { PERMISSIONS_DECISION_CHANNEL } from "
|
|
11
|
-
import type { PermissionSession } from "
|
|
12
|
-
import type { ToolRegistry } from "
|
|
13
|
-
import type { PermissionCheckResult, PermissionState } from "
|
|
8
|
+
import { PermissionGateHandler } from "#src/handlers/permission-gate-handler";
|
|
9
|
+
import type { PermissionDecisionEvent } from "#src/permission-events";
|
|
10
|
+
import { PERMISSIONS_DECISION_CHANNEL } from "#src/permission-events";
|
|
11
|
+
import type { PermissionSession } from "#src/permission-session";
|
|
12
|
+
import type { ToolRegistry } from "#src/tool-registry";
|
|
13
|
+
import type { PermissionCheckResult, PermissionState } from "#src/types";
|
|
14
14
|
|
|
15
15
|
// ── helpers ────────────────────────────────────────────────────────────────
|
|
16
16
|
|
|
@@ -75,7 +75,7 @@ function makeSession(
|
|
|
75
75
|
activate: vi.fn(),
|
|
76
76
|
resolveAgentName: vi.fn().mockReturnValue(null),
|
|
77
77
|
checkPermission: vi.fn().mockReturnValue(makeCheckResult("allow")),
|
|
78
|
-
getToolPermission: vi.fn().mockReturnValue("allow"
|
|
78
|
+
getToolPermission: vi.fn().mockReturnValue("allow"),
|
|
79
79
|
getSessionRuleset: vi.fn().mockReturnValue([]),
|
|
80
80
|
approveSessionRule: vi.fn(),
|
|
81
81
|
getActiveSkillEntries: vi.fn().mockReturnValue([]),
|
|
@@ -4,10 +4,10 @@ import { describe, expect, it, vi } from "vitest";
|
|
|
4
4
|
import {
|
|
5
5
|
getEventInput,
|
|
6
6
|
PermissionGateHandler,
|
|
7
|
-
} from "
|
|
8
|
-
import type { PermissionSession } from "
|
|
9
|
-
import type { ToolRegistry } from "
|
|
10
|
-
import type { PermissionCheckResult, PermissionState } from "
|
|
7
|
+
} from "#src/handlers/permission-gate-handler";
|
|
8
|
+
import type { PermissionSession } from "#src/permission-session";
|
|
9
|
+
import type { ToolRegistry } from "#src/tool-registry";
|
|
10
|
+
import type { PermissionCheckResult, PermissionState } from "#src/types";
|
|
11
11
|
|
|
12
12
|
// ── SDK stubs ──────────────────────────────────────────────────────────────
|
|
13
13
|
vi.mock("@earendil-works/pi-coding-agent", async (importOriginal) => {
|
|
@@ -66,7 +66,7 @@ function makeSession(
|
|
|
66
66
|
activate: vi.fn(),
|
|
67
67
|
resolveAgentName: vi.fn().mockReturnValue(null),
|
|
68
68
|
checkPermission: vi.fn().mockReturnValue(makePermissionResult("allow")),
|
|
69
|
-
getToolPermission: vi.fn().mockReturnValue("allow"
|
|
69
|
+
getToolPermission: vi.fn().mockReturnValue("allow"),
|
|
70
70
|
getSessionRuleset: vi.fn().mockReturnValue([]),
|
|
71
71
|
approveSessionRule: vi.fn(),
|
|
72
72
|
getActiveSkillEntries: vi.fn().mockReturnValue([]),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { normalizeInput } from "
|
|
3
|
-
import { createMcpPermissionTargets } from "
|
|
2
|
+
import { normalizeInput } from "#src/input-normalizer";
|
|
3
|
+
import { createMcpPermissionTargets } from "#src/mcp-targets";
|
|
4
4
|
|
|
5
5
|
describe("normalizeInput — non-MCP surfaces", () => {
|
|
6
6
|
describe("special / path", () => {
|
|
@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
|
|
|
2
2
|
import {
|
|
3
3
|
createMcpPermissionTargets,
|
|
4
4
|
parseQualifiedMcpToolName,
|
|
5
|
-
} from "
|
|
5
|
+
} from "#src/mcp-targets";
|
|
6
6
|
|
|
7
7
|
describe("parseQualifiedMcpToolName", () => {
|
|
8
8
|
it("returns server and tool for a valid qualified name", () => {
|
|
@@ -18,7 +18,7 @@ vi.mock("node:fs", () => ({
|
|
|
18
18
|
default: { existsSync: mockExistsSync },
|
|
19
19
|
}));
|
|
20
20
|
|
|
21
|
-
import { discoverGlobalNodeModulesRoot } from "
|
|
21
|
+
import { discoverGlobalNodeModulesRoot } from "#src/node-modules-discovery";
|
|
22
22
|
|
|
23
23
|
describe("discoverGlobalNodeModulesRoot", () => {
|
|
24
24
|
beforeEach(() => {
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-deprecated -- tests the deprecated RPC channel implementation */
|
|
1
2
|
import { createEventBus } from "@earendil-works/pi-coding-agent";
|
|
2
3
|
import { describe, expect, it, vi } from "vitest";
|
|
3
4
|
import {
|
|
4
5
|
type PermissionRpcDeps,
|
|
5
6
|
registerPermissionRpcHandlers,
|
|
6
|
-
} from "
|
|
7
|
+
} from "#src/permission-event-rpc";
|
|
7
8
|
import type {
|
|
8
9
|
PermissionsCheckReplyData,
|
|
9
10
|
PermissionsRpcReply,
|
|
10
|
-
} from "
|
|
11
|
+
} from "#src/permission-events";
|
|
11
12
|
import {
|
|
12
13
|
PERMISSIONS_PROTOCOL_VERSION,
|
|
13
14
|
PERMISSIONS_RPC_CHECK_CHANNEL,
|
|
14
15
|
PERMISSIONS_RPC_PROMPT_CHANNEL,
|
|
15
|
-
} from "
|
|
16
|
+
} from "#src/permission-events";
|
|
16
17
|
|
|
17
18
|
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
18
19
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-deprecated -- tests the deprecated RPC channel implementation */
|
|
1
2
|
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
2
3
|
import { tmpdir } from "node:os";
|
|
3
4
|
import { dirname, join } from "node:path";
|
|
4
5
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
5
6
|
|
|
6
|
-
import { getGlobalConfigPath } from "
|
|
7
|
-
import piPermissionSystemExtension from "
|
|
7
|
+
import { getGlobalConfigPath } from "#src/config-paths";
|
|
8
|
+
import piPermissionSystemExtension from "#src/index";
|
|
8
9
|
import type {
|
|
9
10
|
PermissionDecisionEvent,
|
|
10
11
|
PermissionsCheckReplyData,
|
|
@@ -13,7 +14,7 @@ import type {
|
|
|
13
14
|
PermissionsPromptRequest,
|
|
14
15
|
PermissionsReadyEvent,
|
|
15
16
|
PermissionsRpcReply,
|
|
16
|
-
} from "
|
|
17
|
+
} from "#src/permission-events";
|
|
17
18
|
import {
|
|
18
19
|
emitDecisionEvent,
|
|
19
20
|
emitReadyEvent,
|
|
@@ -22,7 +23,7 @@ import {
|
|
|
22
23
|
PERMISSIONS_READY_CHANNEL,
|
|
23
24
|
PERMISSIONS_RPC_CHECK_CHANNEL,
|
|
24
25
|
PERMISSIONS_RPC_PROMPT_CHANNEL,
|
|
25
|
-
} from "
|
|
26
|
+
} from "#src/permission-events";
|
|
26
27
|
|
|
27
28
|
// ── Minimal EventBus stub ──────────────────────────────────────────────────
|
|
28
29
|
|
|
@@ -164,6 +165,7 @@ describe("type shapes (PermissionsRpcReply)", () => {
|
|
|
164
165
|
error: "no_ui",
|
|
165
166
|
};
|
|
166
167
|
expect(reply.success).toBe(false);
|
|
168
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- narrowing on discriminated union
|
|
167
169
|
if (!reply.success) {
|
|
168
170
|
expect(reply.error).toBe("no_ui");
|
|
169
171
|
}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
resolvePermissionForwardingTargetSessionId,
|
|
4
4
|
SUBAGENT_PARENT_SESSION_ENV_CANDIDATES,
|
|
5
5
|
SUBAGENT_PARENT_SESSION_ENV_KEY,
|
|
6
|
-
} from "
|
|
6
|
+
} from "#src/permission-forwarding";
|
|
7
7
|
|
|
8
8
|
afterEach(() => {
|
|
9
9
|
vi.unstubAllEnvs();
|
|
@@ -24,6 +24,7 @@ describe("SUBAGENT_PARENT_SESSION_ENV_CANDIDATES", () => {
|
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
test("deprecated SUBAGENT_PARENT_SESSION_ENV_KEY equals the first candidate", () => {
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated -- test verifying the deprecated alias
|
|
27
28
|
expect(SUBAGENT_PARENT_SESSION_ENV_KEY).toBe(
|
|
28
29
|
SUBAGENT_PARENT_SESSION_ENV_CANDIDATES[0],
|
|
29
30
|
);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from "vitest";
|
|
2
|
-
import type { PermissionPromptDecision } from "
|
|
2
|
+
import type { PermissionPromptDecision } from "#src/permission-dialog";
|
|
3
3
|
import {
|
|
4
4
|
applyPermissionGate,
|
|
5
5
|
type PermissionGateParams,
|
|
6
|
-
} from "
|
|
6
|
+
} from "#src/permission-gate";
|
|
7
7
|
|
|
8
8
|
function makeParams(
|
|
9
9
|
overrides: Partial<PermissionGateParams> = {},
|
|
@@ -8,8 +8,8 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
|
8
8
|
import { homedir, tmpdir } from "node:os";
|
|
9
9
|
import { join } from "node:path";
|
|
10
10
|
import { describe, expect, it } from "vitest";
|
|
11
|
-
import { PermissionManager } from "
|
|
12
|
-
import type { Rule, Ruleset } from "
|
|
11
|
+
import { PermissionManager } from "#src/permission-manager";
|
|
12
|
+
import type { Rule, Ruleset } from "#src/rule";
|
|
13
13
|
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
15
|
// Helpers
|
|
@@ -666,9 +666,9 @@ describe("checkPermission — rule origin provenance", () => {
|
|
|
666
666
|
// In-memory PolicyLoader stub tests — no filesystem required
|
|
667
667
|
// ---------------------------------------------------------------------------
|
|
668
668
|
|
|
669
|
-
import type { PolicyLoader } from "
|
|
670
|
-
import type { ResolvedPolicyPaths } from "
|
|
671
|
-
import type { ScopeConfig } from "
|
|
669
|
+
import type { PolicyLoader } from "#src/permission-manager";
|
|
670
|
+
import type { ResolvedPolicyPaths } from "#src/policy-loader";
|
|
671
|
+
import type { ScopeConfig } from "#src/types";
|
|
672
672
|
|
|
673
673
|
/**
|
|
674
674
|
* Minimal in-memory PolicyLoader for testing merge + evaluation logic
|
|
@@ -685,10 +685,12 @@ function createInMemoryPolicyLoader(
|
|
|
685
685
|
): PolicyLoader {
|
|
686
686
|
const issues: string[] = [];
|
|
687
687
|
return {
|
|
688
|
-
loadGlobalConfig: () => scopes.global ?? {},
|
|
689
|
-
loadProjectConfig: () => scopes.project ?? {},
|
|
688
|
+
loadGlobalConfig: () => scopes.global ?? ({} as const),
|
|
689
|
+
loadProjectConfig: () => scopes.project ?? ({} as const),
|
|
690
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- || is intentional: handles both falsy name and missing key
|
|
690
691
|
loadAgentConfig: (name?: string) => (name && scopes.agent?.[name]) || {},
|
|
691
692
|
loadProjectAgentConfig: (name?: string) =>
|
|
693
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- || is intentional: handles both falsy name and missing key
|
|
692
694
|
(name && scopes.projectAgent?.[name]) || {},
|
|
693
695
|
getConfiguredMcpServerNames: () => mcpServerNames,
|
|
694
696
|
getCacheStamp: () => "in-memory",
|
|
@@ -14,13 +14,13 @@ vi.mock("../src/forwarded-permissions/polling", () => ({
|
|
|
14
14
|
// ── Imports (after mocks) ───────────────────────────────────────────────────
|
|
15
15
|
|
|
16
16
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
17
|
-
import { DEFAULT_EXTENSION_CONFIG } from "
|
|
18
|
-
import type { PermissionPromptDecision } from "
|
|
19
|
-
import type { PromptPermissionDetails } from "
|
|
17
|
+
import { DEFAULT_EXTENSION_CONFIG } from "#src/extension-config";
|
|
18
|
+
import type { PermissionPromptDecision } from "#src/permission-dialog";
|
|
19
|
+
import type { PromptPermissionDetails } from "#src/permission-prompter";
|
|
20
20
|
import {
|
|
21
21
|
PermissionPrompter,
|
|
22
22
|
type PermissionPrompterDeps,
|
|
23
|
-
} from "
|
|
23
|
+
} from "#src/permission-prompter";
|
|
24
24
|
|
|
25
25
|
// ── Helpers ─────────────────────────────────────────────────────────────────
|
|
26
26
|
|
|
@@ -11,10 +11,10 @@ import {
|
|
|
11
11
|
formatSkillAskPrompt,
|
|
12
12
|
formatSkillPathAskPrompt,
|
|
13
13
|
formatUnknownToolReason,
|
|
14
|
-
} from "
|
|
15
|
-
import type { SkillPromptEntry } from "
|
|
16
|
-
import { formatToolInputForPrompt } from "
|
|
17
|
-
import type { PermissionCheckResult } from "
|
|
14
|
+
} from "#src/permission-prompts";
|
|
15
|
+
import type { SkillPromptEntry } from "#src/skill-prompt-sanitizer";
|
|
16
|
+
import { formatToolInputForPrompt } from "#src/tool-input-preview";
|
|
17
|
+
import type { PermissionCheckResult } from "#src/types";
|
|
18
18
|
|
|
19
19
|
const mockedFormatToolInput = vi.mocked(formatToolInputForPrompt);
|
|
20
20
|
|
|
@@ -29,16 +29,16 @@ vi.mock("../src/runtime", async (importOriginal) => {
|
|
|
29
29
|
|
|
30
30
|
// ── Test helpers ───────────────────────────────────────────────────────────
|
|
31
31
|
|
|
32
|
-
import type { ExtensionPaths } from "
|
|
33
|
-
import type { ForwardingController } from "
|
|
34
|
-
import type { PermissionManager } from "
|
|
32
|
+
import type { ExtensionPaths } from "#src/extension-paths";
|
|
33
|
+
import type { ForwardingController } from "#src/forwarding-manager";
|
|
34
|
+
import type { PermissionManager } from "#src/permission-manager";
|
|
35
35
|
import {
|
|
36
36
|
PermissionSession,
|
|
37
37
|
type PermissionSessionRuntimeDeps,
|
|
38
|
-
} from "
|
|
39
|
-
import type { SessionLogger } from "
|
|
40
|
-
import type { SkillPromptEntry } from "
|
|
41
|
-
import type { PermissionCheckResult } from "
|
|
38
|
+
} from "#src/permission-session";
|
|
39
|
+
import type { SessionLogger } from "#src/session-logger";
|
|
40
|
+
import type { SkillPromptEntry } from "#src/skill-prompt-sanitizer";
|
|
41
|
+
import type { PermissionCheckResult } from "#src/types";
|
|
42
42
|
|
|
43
43
|
function makeSkillEntry(
|
|
44
44
|
name: string,
|
|
@@ -122,7 +122,7 @@ function makePermissionManager(
|
|
|
122
122
|
toolName: "read",
|
|
123
123
|
source: "tool",
|
|
124
124
|
origin: "builtin",
|
|
125
|
-
}
|
|
125
|
+
}),
|
|
126
126
|
getToolPermission: vi.fn().mockReturnValue("allow"),
|
|
127
127
|
getConfigIssues: vi.fn().mockReturnValue([]),
|
|
128
128
|
getPolicyCacheStamp: vi.fn().mockReturnValue("stamp-1"),
|
|
@@ -260,7 +260,7 @@ describe("PermissionSession", () => {
|
|
|
260
260
|
toolName: "bash",
|
|
261
261
|
source: "bash",
|
|
262
262
|
origin: "global",
|
|
263
|
-
}
|
|
263
|
+
}),
|
|
264
264
|
});
|
|
265
265
|
mockCreatePermissionManagerForCwd.mockReturnValue(pm2);
|
|
266
266
|
const { session } = createSession();
|
|
@@ -14,39 +14,39 @@ import {
|
|
|
14
14
|
createActiveToolsCacheKey,
|
|
15
15
|
createBeforeAgentStartPromptStateKey,
|
|
16
16
|
shouldApplyCachedAgentStartState,
|
|
17
|
-
} from "
|
|
18
|
-
import { getGlobalConfigPath } from "
|
|
19
|
-
import { DEFAULT_EXTENSION_CONFIG } from "
|
|
20
|
-
import piPermissionSystemExtension from "
|
|
21
|
-
import { createPermissionSystemLogger } from "
|
|
17
|
+
} from "#src/before-agent-start-cache";
|
|
18
|
+
import { getGlobalConfigPath } from "#src/config-paths";
|
|
19
|
+
import { DEFAULT_EXTENSION_CONFIG } from "#src/extension-config";
|
|
20
|
+
import piPermissionSystemExtension from "#src/index";
|
|
21
|
+
import { createPermissionSystemLogger } from "#src/logging";
|
|
22
22
|
import {
|
|
23
23
|
createPermissionForwardingLocation,
|
|
24
24
|
isForwardedPermissionRequestForSession,
|
|
25
25
|
resolvePermissionForwardingTargetSessionId,
|
|
26
26
|
SUBAGENT_ENV_HINT_KEYS,
|
|
27
27
|
SUBAGENT_PARENT_SESSION_ENV_KEY,
|
|
28
|
-
} from "
|
|
29
|
-
import { PermissionManager } from "
|
|
28
|
+
} from "#src/permission-forwarding";
|
|
29
|
+
import { PermissionManager } from "#src/permission-manager";
|
|
30
30
|
import {
|
|
31
31
|
findSkillPathMatch,
|
|
32
32
|
parseAllSkillPromptSections,
|
|
33
33
|
resolveSkillPromptEntries,
|
|
34
|
-
} from "
|
|
35
|
-
import { getPermissionSystemStatus } from "
|
|
36
|
-
import { sanitizeAvailableToolsSection } from "
|
|
34
|
+
} from "#src/skill-prompt-sanitizer";
|
|
35
|
+
import { getPermissionSystemStatus } from "#src/status";
|
|
36
|
+
import { sanitizeAvailableToolsSection } from "#src/system-prompt-sanitizer";
|
|
37
37
|
import {
|
|
38
38
|
checkRequestedToolRegistration,
|
|
39
39
|
getToolNameFromValue,
|
|
40
|
-
} from "
|
|
40
|
+
} from "#src/tool-registry";
|
|
41
41
|
import type {
|
|
42
42
|
PermissionCheckResult,
|
|
43
43
|
PermissionState,
|
|
44
44
|
ScopeConfig,
|
|
45
|
-
} from "
|
|
45
|
+
} from "#src/types";
|
|
46
46
|
import {
|
|
47
47
|
canResolveAskPermissionRequest,
|
|
48
48
|
shouldAutoApprovePermissionState,
|
|
49
|
-
} from "
|
|
49
|
+
} from "#src/yolo-mode";
|
|
50
50
|
|
|
51
51
|
type CreateManagerOptions = {
|
|
52
52
|
mcpServerNames?: readonly string[];
|
|
@@ -112,6 +112,7 @@ type ExtensionHarnessOptions = {
|
|
|
112
112
|
|
|
113
113
|
const INHERITED_SUBAGENT_ENV_KEYS = [
|
|
114
114
|
...SUBAGENT_ENV_HINT_KEYS,
|
|
115
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated -- test uses deprecated alias intentionally
|
|
115
116
|
SUBAGENT_PARENT_SESSION_ENV_KEY,
|
|
116
117
|
] as const;
|
|
117
118
|
|
|
@@ -121,6 +122,7 @@ async function withIsolatedSubagentEnv<T>(
|
|
|
121
122
|
const originalValues = new Map<string, string | undefined>();
|
|
122
123
|
for (const key of INHERITED_SUBAGENT_ENV_KEYS) {
|
|
123
124
|
originalValues.set(key, process.env[key]);
|
|
125
|
+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete -- process.env cleanup requires dynamic delete
|
|
124
126
|
delete process.env[key];
|
|
125
127
|
}
|
|
126
128
|
|
|
@@ -129,6 +131,7 @@ async function withIsolatedSubagentEnv<T>(
|
|
|
129
131
|
} finally {
|
|
130
132
|
for (const [key, value] of originalValues.entries()) {
|
|
131
133
|
if (value === undefined) {
|
|
134
|
+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete -- process.env cleanup requires dynamic delete
|
|
132
135
|
delete process.env[key];
|
|
133
136
|
} else {
|
|
134
137
|
process.env[key] = value;
|
|
@@ -143,7 +146,7 @@ function createToolCallHarness(
|
|
|
143
146
|
options: ExtensionHarnessOptions = {},
|
|
144
147
|
): ExtensionHarness {
|
|
145
148
|
const baseDir = mkdtempSync(join(tmpdir(), "pi-permission-system-runtime-"));
|
|
146
|
-
const cwd = options.cwd
|
|
149
|
+
const cwd = options.cwd ?? baseDir;
|
|
147
150
|
const prompts: string[] = [];
|
|
148
151
|
const handlers: Record<string, MockHandler> = {};
|
|
149
152
|
const originalAgentDir = process.env.PI_CODING_AGENT_DIR;
|
|
@@ -188,10 +191,7 @@ function createToolCallHarness(
|
|
|
188
191
|
prompts,
|
|
189
192
|
cleanup: async (): Promise<void> => {
|
|
190
193
|
await Promise.resolve(
|
|
191
|
-
handlers.session_shutdown
|
|
192
|
-
{},
|
|
193
|
-
createMockContext(cwd, prompts, options),
|
|
194
|
-
),
|
|
194
|
+
handlers.session_shutdown({}, createMockContext(cwd, prompts, options)),
|
|
195
195
|
);
|
|
196
196
|
rmSync(baseDir, { recursive: true, force: true });
|
|
197
197
|
},
|
|
@@ -236,7 +236,7 @@ async function runToolCall(
|
|
|
236
236
|
handler(event, createMockContext(harness.cwd, harness.prompts, options)),
|
|
237
237
|
),
|
|
238
238
|
);
|
|
239
|
-
return
|
|
239
|
+
return result ?? {};
|
|
240
240
|
}
|
|
241
241
|
|
|
242
242
|
test("Yolo mode only auto-approves ask-state permissions", () => {
|
|
@@ -1515,7 +1515,7 @@ test("REGRESSION: resolveSkillPromptEntries sanitizes every available_skills blo
|
|
|
1515
1515
|
|
|
1516
1516
|
expect(result.prompt).not.toContain("denied-skill");
|
|
1517
1517
|
expect(result.prompt).toContain("visible-skill");
|
|
1518
|
-
expect((result.prompt.match(/<available_skills>/g)
|
|
1518
|
+
expect((result.prompt.match(/<available_skills>/g) ?? []).length).toBe(1);
|
|
1519
1519
|
expect(result.entries.map((entry) => entry.name)).toEqual([
|
|
1520
1520
|
"visible-skill",
|
|
1521
1521
|
]);
|
|
@@ -2371,7 +2371,7 @@ test("session approval: session_shutdown clears session approvals", async () =>
|
|
|
2371
2371
|
hasUI: true,
|
|
2372
2372
|
selectResponse: "Yes",
|
|
2373
2373
|
});
|
|
2374
|
-
await Promise.resolve(harness.handlers.session_shutdown
|
|
2374
|
+
await Promise.resolve(harness.handlers.session_shutdown({}, shutdownCtx));
|
|
2375
2375
|
|
|
2376
2376
|
// Access same path again — should prompt because cache was cleared
|
|
2377
2377
|
const result = await runToolCall(
|
|
@@ -15,8 +15,8 @@ vi.mock("node:child_process", () => ({
|
|
|
15
15
|
default: { spawnSync: mockSpawnSync },
|
|
16
16
|
}));
|
|
17
17
|
|
|
18
|
-
import { discoverGlobalNodeModulesRoot } from "
|
|
19
|
-
import { isPiInfrastructureRead } from "
|
|
18
|
+
import { discoverGlobalNodeModulesRoot } from "#src/node-modules-discovery";
|
|
19
|
+
import { isPiInfrastructureRead } from "#src/path-utils";
|
|
20
20
|
|
|
21
21
|
// ── discoverGlobalNodeModulesRoot ──────────────────────────────────────────
|
|
22
22
|
|
|
@@ -2,7 +2,7 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { describe, expect, it } from "vitest";
|
|
5
|
-
import { FilePolicyLoader } from "
|
|
5
|
+
import { FilePolicyLoader } from "#src/policy-loader";
|
|
6
6
|
|
|
7
7
|
// ---------------------------------------------------------------------------
|
|
8
8
|
// Helpers
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, test } from "vitest";
|
|
2
|
-
import type { Rule, RuleOrigin, Ruleset } from "
|
|
3
|
-
import { evaluate, evaluateFirst, evaluateMostRestrictive } from "
|
|
2
|
+
import type { Rule, RuleOrigin, Ruleset } from "#src/rule";
|
|
3
|
+
import { evaluate, evaluateFirst, evaluateMostRestrictive } from "#src/rule";
|
|
4
4
|
|
|
5
5
|
describe("evaluate", () => {
|
|
6
6
|
const allowBashGit: Rule = {
|
|
@@ -71,15 +71,15 @@ import {
|
|
|
71
71
|
getGlobalConfigPath,
|
|
72
72
|
getGlobalLogsDir,
|
|
73
73
|
getProjectConfigPath,
|
|
74
|
-
} from "
|
|
75
|
-
import { DEFAULT_EXTENSION_CONFIG } from "
|
|
76
|
-
import { PermissionManager } from "
|
|
74
|
+
} from "#src/config-paths";
|
|
75
|
+
import { DEFAULT_EXTENSION_CONFIG } from "#src/extension-config";
|
|
76
|
+
import { PermissionManager } from "#src/permission-manager";
|
|
77
77
|
import {
|
|
78
78
|
createExtensionRuntime,
|
|
79
79
|
createPermissionManagerForCwd,
|
|
80
80
|
derivePiProjectPaths,
|
|
81
81
|
refreshExtensionConfig,
|
|
82
|
-
} from "
|
|
82
|
+
} from "#src/runtime";
|
|
83
83
|
|
|
84
84
|
// ── test suite ─────────────────────────────────────────────────────────────
|
|
85
85
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { buildInputForSurface } from "
|
|
3
|
-
import type { PermissionsService } from "
|
|
2
|
+
import { buildInputForSurface } from "#src/input-normalizer";
|
|
3
|
+
import type { PermissionsService } from "#src/service";
|
|
4
4
|
import {
|
|
5
5
|
getPermissionsService,
|
|
6
6
|
publishPermissionsService,
|
|
7
7
|
unpublishPermissionsService,
|
|
8
|
-
} from "
|
|
9
|
-
import type { PermissionCheckResult } from "
|
|
8
|
+
} from "#src/service";
|
|
9
|
+
import type { PermissionCheckResult } from "#src/types";
|
|
10
10
|
|
|
11
11
|
// ── helpers ────────────────────────────────────────────────────────────────
|
|
12
12
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from "vitest";
|
|
2
|
-
import type { ExtensionRuntime } from "
|
|
3
|
-
import { createSessionLogger } from "
|
|
2
|
+
import type { ExtensionRuntime } from "#src/runtime";
|
|
3
|
+
import { createSessionLogger } from "#src/session-logger";
|
|
4
4
|
|
|
5
5
|
// ── helpers ────────────────────────────────────────────────────────────────
|
|
6
6
|
|