@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.
Files changed (98) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/package.json +7 -3
  3. package/src/active-agent.ts +1 -1
  4. package/src/bash-arity.ts +1 -0
  5. package/src/config-modal.ts +2 -0
  6. package/src/forwarded-permissions/io.ts +4 -2
  7. package/src/forwarded-permissions/polling.ts +8 -7
  8. package/src/handlers/before-agent-start.ts +7 -6
  9. package/src/handlers/gates/bash-external-directory.ts +4 -4
  10. package/src/handlers/gates/bash-path-extractor.ts +4 -6
  11. package/src/handlers/gates/bash-path.ts +5 -5
  12. package/src/handlers/gates/descriptor.ts +6 -6
  13. package/src/handlers/gates/external-directory.ts +2 -2
  14. package/src/handlers/gates/helpers.ts +2 -2
  15. package/src/handlers/gates/path.ts +4 -4
  16. package/src/handlers/gates/runner.ts +7 -4
  17. package/src/handlers/gates/skill-read.ts +5 -5
  18. package/src/handlers/gates/tool.ts +5 -5
  19. package/src/handlers/lifecycle.ts +9 -8
  20. package/src/handlers/permission-gate-handler.ts +12 -7
  21. package/src/logging.ts +3 -0
  22. package/src/node-modules-discovery.ts +1 -1
  23. package/src/normalize.ts +1 -0
  24. package/src/permission-event-rpc.ts +2 -0
  25. package/src/permission-manager.ts +7 -6
  26. package/src/permission-merge.ts +4 -2
  27. package/src/permission-prompter.ts +3 -0
  28. package/src/permission-prompts.ts +1 -1
  29. package/src/policy-loader.ts +5 -5
  30. package/src/service.ts +1 -0
  31. package/src/skill-prompt-sanitizer.ts +3 -3
  32. package/src/tool-registry.ts +1 -1
  33. package/src/wildcard-matcher.ts +2 -2
  34. package/src/yolo-mode.ts +2 -1
  35. package/{tests → test}/active-agent.test.ts +1 -1
  36. package/{tests → test}/bash-arity.test.ts +4 -4
  37. package/{tests → test}/bash-external-directory.test.ts +3 -3
  38. package/{tests → test}/common.test.ts +1 -1
  39. package/{tests → test}/config-loader.test.ts +1 -1
  40. package/{tests → test}/config-modal.test.ts +9 -11
  41. package/{tests → test}/config-paths.test.ts +1 -1
  42. package/{tests → test}/config-reporter.test.ts +4 -4
  43. package/{tests → test}/denial-messages.test.ts +2 -2
  44. package/{tests → test}/expand-home.test.ts +1 -1
  45. package/{tests → test}/extension-config.test.ts +1 -1
  46. package/{tests → test}/extension-paths.test.ts +2 -2
  47. package/{tests → test}/forwarded-permissions/io.test.ts +2 -2
  48. package/{tests → test}/forwarding-manager.test.ts +1 -1
  49. package/{tests → test}/handlers/before-agent-start.test.ts +5 -5
  50. package/{tests → test}/handlers/external-directory-integration.test.ts +8 -8
  51. package/{tests → test}/handlers/external-directory-session-dedup.test.ts +6 -6
  52. package/{tests → test}/handlers/gates/bash-external-directory.test.ts +5 -8
  53. package/{tests → test}/handlers/gates/bash-path.test.ts +6 -9
  54. package/{tests → test}/handlers/gates/external-directory-messages.test.ts +1 -1
  55. package/{tests → test}/handlers/gates/external-directory.test.ts +4 -7
  56. package/{tests → test}/handlers/gates/helpers.test.ts +1 -1
  57. package/{tests → test}/handlers/gates/path.test.ts +6 -6
  58. package/{tests → test}/handlers/gates/runner.test.ts +5 -5
  59. package/{tests → test}/handlers/gates/skill-read.test.ts +12 -14
  60. package/{tests → test}/handlers/gates/tool.test.ts +4 -4
  61. package/{tests → test}/handlers/input-events.test.ts +7 -7
  62. package/{tests → test}/handlers/input.test.ts +5 -5
  63. package/{tests → test}/handlers/lifecycle.test.ts +2 -2
  64. package/{tests → test}/handlers/tool-call-events.test.ts +7 -7
  65. package/{tests → test}/handlers/tool-call.test.ts +5 -5
  66. package/{tests → test}/input-normalizer.test.ts +2 -2
  67. package/{tests → test}/mcp-targets.test.ts +1 -1
  68. package/{tests → test}/node-modules-discovery.test.ts +1 -1
  69. package/{tests → test}/normalize.test.ts +1 -1
  70. package/{tests → test}/path-utils.test.ts +1 -1
  71. package/{tests → test}/pattern-suggest.test.ts +1 -1
  72. package/{tests → test}/permission-dialog.test.ts +1 -1
  73. package/{tests → test}/permission-event-rpc.test.ts +4 -3
  74. package/{tests → test}/permission-events.test.ts +6 -4
  75. package/{tests → test}/permission-forwarding.test.ts +2 -1
  76. package/{tests → test}/permission-gate.test.ts +2 -2
  77. package/{tests → test}/permission-manager-unified.test.ts +9 -7
  78. package/{tests → test}/permission-merge.test.ts +1 -1
  79. package/{tests → test}/permission-prompter.test.ts +4 -4
  80. package/{tests → test}/permission-prompts.test.ts +4 -4
  81. package/{tests → test}/permission-session.test.ts +9 -9
  82. package/{tests → test}/permission-system.test.ts +21 -21
  83. package/{tests → test}/pi-infrastructure-read.test.ts +2 -2
  84. package/{tests → test}/policy-loader.test.ts +1 -1
  85. package/{tests → test}/rule.test.ts +2 -2
  86. package/{tests → test}/runtime.test.ts +4 -4
  87. package/{tests → test}/service.test.ts +4 -4
  88. package/{tests → test}/session-logger.test.ts +2 -2
  89. package/{tests → test}/session-rules.test.ts +2 -2
  90. package/{tests → test}/session-start.test.ts +4 -4
  91. package/{tests → test}/skill-prompt-sanitizer.test.ts +3 -3
  92. package/{tests → test}/subagent-context.test.ts +2 -2
  93. package/{tests → test}/synthesize.test.ts +3 -3
  94. package/{tests → test}/system-prompt-sanitizer.test.ts +1 -1
  95. package/{tests → test}/tool-input-preview.test.ts +3 -3
  96. package/{tests → test}/tool-registry.test.ts +1 -1
  97. package/{tests → test}/wildcard-matcher.test.ts +1 -1
  98. 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 "../../../src/handlers/gates/tool";
4
- import type { ToolCallContext } from "../../../src/handlers/gates/types";
5
- import type { PermissionCheckResult } from "../../../src/types";
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!.agentName).toBe("my-agent");
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 "../../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";
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" as PermissionState),
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 "../../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";
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" as PermissionState),
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 "../../src/handlers/lifecycle";
4
- import type { PermissionSession } from "../../src/permission-session";
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 "../../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";
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" as PermissionState),
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 "../../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";
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" as PermissionState),
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 "../src/input-normalizer";
3
- import { createMcpPermissionTargets } from "../src/mcp-targets";
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 "../src/mcp-targets";
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 "../src/node-modules-discovery";
21
+ import { discoverGlobalNodeModulesRoot } from "#src/node-modules-discovery";
22
22
 
23
23
  describe("discoverGlobalNodeModulesRoot", () => {
24
24
  beforeEach(() => {
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, test } from "vitest";
2
- import { normalizeFlatConfig } from "../src/normalize";
2
+ import { normalizeFlatConfig } from "#src/normalize";
3
3
 
4
4
  describe("normalizeFlatConfig", () => {
5
5
  describe("string shorthand", () => {
@@ -20,7 +20,7 @@ import {
20
20
  PATH_BEARING_TOOLS,
21
21
  READ_ONLY_PATH_BEARING_TOOLS,
22
22
  SAFE_SYSTEM_PATHS,
23
- } from "../src/path-utils";
23
+ } from "#src/path-utils";
24
24
 
25
25
  describe("normalizePathForComparison", () => {
26
26
  const cwd = "/projects/my-app";
@@ -3,7 +3,7 @@ import {
3
3
  suggestBashPattern,
4
4
  suggestMcpPattern,
5
5
  suggestSessionPattern,
6
- } from "../src/pattern-suggest";
6
+ } from "#src/pattern-suggest";
7
7
 
8
8
  describe("suggestBashPattern", () => {
9
9
  it("returns <command> <subcommand> * using the arity table", () => {
@@ -5,7 +5,7 @@ import {
5
5
  normalizePermissionDenialReason,
6
6
  type PermissionDecisionUi,
7
7
  requestPermissionDecisionFromUi,
8
- } from "../src/permission-dialog";
8
+ } from "#src/permission-dialog";
9
9
 
10
10
  describe("isPermissionDecisionState", () => {
11
11
  it("accepts approved", () => {
@@ -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 "../src/permission-event-rpc";
7
+ } from "#src/permission-event-rpc";
7
8
  import type {
8
9
  PermissionsCheckReplyData,
9
10
  PermissionsRpcReply,
10
- } from "../src/permission-events";
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 "../src/permission-events";
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 "../src/config-paths";
7
- import piPermissionSystemExtension from "../src/index";
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 "../src/permission-events";
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 "../src/permission-events";
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 "../src/permission-forwarding";
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 "../src/permission-dialog";
2
+ import type { PermissionPromptDecision } from "#src/permission-dialog";
3
3
  import {
4
4
  applyPermissionGate,
5
5
  type PermissionGateParams,
6
- } from "../src/permission-gate";
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 "../src/permission-manager";
12
- import type { Rule, Ruleset } from "../src/rule";
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 "../src/permission-manager";
670
- import type { ResolvedPolicyPaths } from "../src/policy-loader";
671
- import type { ScopeConfig } from "../src/types";
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",
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, test } from "vitest";
2
2
 
3
- import { mergeFlatPermissions } from "../src/permission-merge";
3
+ import { mergeFlatPermissions } from "#src/permission-merge";
4
4
 
5
5
  describe("mergeFlatPermissions", () => {
6
6
  test("string replaces string", () => {
@@ -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 "../src/extension-config";
18
- import type { PermissionPromptDecision } from "../src/permission-dialog";
19
- import type { PromptPermissionDetails } from "../src/permission-prompter";
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 "../src/permission-prompter";
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 "../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";
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 "../src/extension-paths";
33
- import type { ForwardingController } from "../src/forwarding-manager";
34
- import type { PermissionManager } from "../src/permission-manager";
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 "../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";
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
- } as PermissionCheckResult),
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
- } as PermissionCheckResult),
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 "../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";
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 "../src/permission-forwarding";
29
- import { PermissionManager } from "../src/permission-manager";
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 "../src/skill-prompt-sanitizer";
35
- import { getPermissionSystemStatus } from "../src/status";
36
- import { sanitizeAvailableToolsSection } from "../src/system-prompt-sanitizer";
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 "../src/tool-registry";
40
+ } from "#src/tool-registry";
41
41
  import type {
42
42
  PermissionCheckResult,
43
43
  PermissionState,
44
44
  ScopeConfig,
45
- } from "../src/types";
45
+ } from "#src/types";
46
46
  import {
47
47
  canResolveAskPermissionRequest,
48
48
  shouldAutoApprovePermissionState,
49
- } from "../src/yolo-mode";
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 || baseDir;
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 (result ?? {}) as Record<string, unknown>;
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) || []).length).toBe(1);
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?.({}, shutdownCtx));
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 "../src/node-modules-discovery";
19
- import { isPiInfrastructureRead } from "../src/path-utils";
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 "../src/policy-loader";
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 "../src/rule";
3
- import { evaluate, evaluateFirst, evaluateMostRestrictive } from "../src/rule";
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 "../src/config-paths";
75
- import { DEFAULT_EXTENSION_CONFIG } from "../src/extension-config";
76
- import { PermissionManager } from "../src/permission-manager";
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 "../src/runtime";
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 "../src/input-normalizer";
3
- import type { PermissionsService } from "../src/service";
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 "../src/service";
9
- import type { PermissionCheckResult } from "../src/types";
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 "../src/runtime";
3
- import { createSessionLogger } from "../src/session-logger";
2
+ import type { ExtensionRuntime } from "#src/runtime";
3
+ import { createSessionLogger } from "#src/session-logger";
4
4
 
5
5
  // ── helpers ────────────────────────────────────────────────────────────────
6
6