@gotgenes/pi-permission-system 4.7.0 → 4.9.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.
@@ -11,6 +11,7 @@ const {
11
11
  mockGetActiveAgentName,
12
12
  mockGetActiveAgentNameFromSystemPrompt,
13
13
  mockBuildResolvedConfigLogEntry,
14
+ mockDiscoverGlobalNodeModulesRoot,
14
15
  } = vi.hoisted(() => ({
15
16
  mockLoggerDebug:
16
17
  vi.fn<
@@ -27,6 +28,7 @@ const {
27
28
  mockGetActiveAgentNameFromSystemPrompt:
28
29
  vi.fn<(prompt?: string) => string | null>(),
29
30
  mockBuildResolvedConfigLogEntry: vi.fn(),
31
+ mockDiscoverGlobalNodeModulesRoot: vi.fn<() => string | null>(),
30
32
  }));
31
33
 
32
34
  vi.mock("../src/logging", () => ({
@@ -65,6 +67,10 @@ vi.mock("../src/subagent-context", () => ({
65
67
  isSubagentExecutionContext: vi.fn().mockReturnValue(false),
66
68
  }));
67
69
 
70
+ vi.mock("../src/external-directory", () => ({
71
+ discoverGlobalNodeModulesRoot: mockDiscoverGlobalNodeModulesRoot,
72
+ }));
73
+
68
74
  vi.mock("../src/session-rules", () => ({
69
75
  SessionRules: vi.fn(),
70
76
  deriveApprovalPattern: vi.fn(),
@@ -99,6 +105,10 @@ describe("createExtensionRuntime", () => {
99
105
  debug: mockLoggerDebug,
100
106
  review: mockLoggerReview,
101
107
  });
108
+ mockDiscoverGlobalNodeModulesRoot.mockReset();
109
+ mockDiscoverGlobalNodeModulesRoot.mockReturnValue(
110
+ "/mock/global/node_modules",
111
+ );
102
112
  });
103
113
 
104
114
  // ── Path derivation ──────────────────────────────────────────────────────
@@ -130,6 +140,41 @@ describe("createExtensionRuntime", () => {
130
140
  expect(runtime.globalLogsDir).toBe(getGlobalLogsDir("/test/agent"));
131
141
  });
132
142
 
143
+ // ── piInfrastructureDirs ─────────────────────────────────────────────────
144
+
145
+ it("includes agentDir in piInfrastructureDirs", () => {
146
+ const runtime = createExtensionRuntime({ agentDir: "/test/agent" });
147
+ expect(runtime.piInfrastructureDirs).toContain("/test/agent");
148
+ });
149
+
150
+ it("includes agentDir/git in piInfrastructureDirs", () => {
151
+ const runtime = createExtensionRuntime({ agentDir: "/test/agent" });
152
+ expect(runtime.piInfrastructureDirs).toContain("/test/agent/git");
153
+ });
154
+
155
+ it("includes discovered global node_modules root in piInfrastructureDirs", () => {
156
+ const runtime = createExtensionRuntime({ agentDir: "/test/agent" });
157
+ expect(runtime.piInfrastructureDirs).toContain("/mock/global/node_modules");
158
+ });
159
+
160
+ it("excludes null when discoverGlobalNodeModulesRoot returns null", () => {
161
+ mockDiscoverGlobalNodeModulesRoot.mockReturnValue(null);
162
+ const runtime = createExtensionRuntime({ agentDir: "/test/agent" });
163
+ for (const dir of runtime.piInfrastructureDirs) {
164
+ expect(dir).not.toBeNull();
165
+ expect(typeof dir).toBe("string");
166
+ }
167
+ });
168
+
169
+ it("omits global node_modules from piInfrastructureDirs when discovery returns null", () => {
170
+ mockDiscoverGlobalNodeModulesRoot.mockReturnValue(null);
171
+ const runtime = createExtensionRuntime({ agentDir: "/test/agent" });
172
+ // Only agentDir and agentDir/git should be present.
173
+ expect(runtime.piInfrastructureDirs).toHaveLength(2);
174
+ expect(runtime.piInfrastructureDirs).toContain("/test/agent");
175
+ expect(runtime.piInfrastructureDirs).toContain("/test/agent/git");
176
+ });
177
+
133
178
  // ── Default mutable state ────────────────────────────────────────────────
134
179
 
135
180
  it("initializes config to DEFAULT_EXTENSION_CONFIG", () => {
@@ -1,5 +1,15 @@
1
+ import { join } from "node:path";
1
2
  import { afterEach, describe, expect, test, vi } from "vitest";
2
3
 
4
+ const mockHomedir = vi.hoisted(() => vi.fn(() => "/home/testuser"));
5
+
6
+ vi.mock("node:os", () => ({
7
+ homedir: mockHomedir,
8
+ default: { homedir: mockHomedir },
9
+ }));
10
+
11
+ const FAKE_HOME = "/home/testuser";
12
+
3
13
  import {
4
14
  compileWildcardPattern,
5
15
  compileWildcardPatternEntries,
@@ -9,6 +19,7 @@ import {
9
19
  } from "../src/wildcard-matcher";
10
20
 
11
21
  afterEach(() => {
22
+ mockHomedir.mockClear();
12
23
  vi.restoreAllMocks();
13
24
  });
14
25
 
@@ -233,3 +244,50 @@ describe("wildcardMatch", () => {
233
244
  expect(wildcardMatch("tool.name", "toolXname")).toBe(false);
234
245
  });
235
246
  });
247
+
248
+ describe("home path expansion in patterns", () => {
249
+ test("wildcardMatch expands ~ prefix in pattern before matching", () => {
250
+ const expandedPath = join(FAKE_HOME, "dev/project");
251
+ expect(wildcardMatch("~/dev/project", expandedPath)).toBe(true);
252
+ });
253
+
254
+ test("wildcardMatch expands ~/glob in pattern", () => {
255
+ const expandedFile = join(FAKE_HOME, "dev/project/file.ts");
256
+ expect(wildcardMatch("~/dev/*", expandedFile)).toBe(true);
257
+ });
258
+
259
+ test("wildcardMatch ~/glob does not match a different home directory", () => {
260
+ expect(wildcardMatch("~/dev/*", "/other/user/dev/file.ts")).toBe(false);
261
+ });
262
+
263
+ test("wildcardMatch expands $HOME prefix in pattern before matching", () => {
264
+ const expandedPath = join(FAKE_HOME, "dev/project");
265
+ expect(wildcardMatch("$HOME/dev/project", expandedPath)).toBe(true);
266
+ });
267
+
268
+ test("wildcardMatch expands $HOME/glob in pattern", () => {
269
+ const expandedFile = join(FAKE_HOME, "work/file.ts");
270
+ expect(wildcardMatch("$HOME/work/*", expandedFile)).toBe(true);
271
+ });
272
+
273
+ test("compileWildcardPattern retains original ~ pattern in .pattern field", () => {
274
+ const compiled = compileWildcardPattern("~/dev/*", "allow");
275
+ expect(compiled.pattern).toBe("~/dev/*");
276
+ });
277
+
278
+ test("compileWildcardPattern retains original $HOME pattern in .pattern field", () => {
279
+ const compiled = compileWildcardPattern("$HOME/dev/*", "allow");
280
+ expect(compiled.pattern).toBe("$HOME/dev/*");
281
+ });
282
+
283
+ test("compileWildcardPattern expanded regex matches the expanded path", () => {
284
+ const compiled = compileWildcardPattern("~/dev/*", "allow");
285
+ const expandedFile = join(FAKE_HOME, "dev/file.ts");
286
+ expect(compiled.regex.test(expandedFile)).toBe(true);
287
+ });
288
+
289
+ test("non-home pattern is unaffected", () => {
290
+ expect(wildcardMatch("/absolute/path/*", "/absolute/path/file")).toBe(true);
291
+ expect(wildcardMatch("/absolute/path/*", "/other/file")).toBe(false);
292
+ });
293
+ });