@gotgenes/pi-permission-system 5.4.0 → 5.5.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.
@@ -1,9 +1,10 @@
1
1
  import { describe, expect, it, vi } from "vitest";
2
2
 
3
3
  import { evaluateSkillReadGate } from "../../../src/handlers/gates/skill-read";
4
- import type { ToolCallContext } from "../../../src/handlers/gates/types";
5
- import type { HandlerDeps } from "../../../src/handlers/types";
6
- import type { PermissionEventBus } from "../../../src/permission-events";
4
+ import type {
5
+ SkillReadGateDeps,
6
+ ToolCallContext,
7
+ } from "../../../src/handlers/gates/types";
7
8
  import type { SkillPromptEntry } from "../../../src/skill-prompt-sanitizer";
8
9
 
9
10
  // ── SDK stubs ──────────────────────────────────────────────────────────────
@@ -40,31 +41,19 @@ function makeTcc(overrides: Partial<ToolCallContext> = {}): ToolCallContext {
40
41
  };
41
42
  }
42
43
 
43
- function makeEvents(): PermissionEventBus {
44
- return { emit: vi.fn(), on: vi.fn().mockReturnValue(() => undefined) };
45
- }
46
-
47
- function makeRuntime(
48
- overrides: Record<string, unknown> = {},
49
- ): HandlerDeps["runtime"] {
44
+ function makeSkillReadGateDeps(
45
+ overrides: Partial<SkillReadGateDeps> = {},
46
+ ): SkillReadGateDeps {
50
47
  return {
51
- activeSkillEntries: [],
48
+ getActiveSkillEntries: vi.fn().mockReturnValue([]),
52
49
  writeReviewLog: vi.fn(),
53
- ...overrides,
54
- } as unknown as HandlerDeps["runtime"];
55
- }
56
-
57
- function makeDeps(overrides: Record<string, unknown> = {}): HandlerDeps {
58
- const { runtime: runtimeOverrides, events, ...rest } = overrides;
59
- return {
60
- runtime: makeRuntime(runtimeOverrides as Record<string, unknown>),
61
- events: events ?? makeEvents(),
62
- canRequestPermissionConfirmation: vi.fn().mockReturnValue(true),
50
+ emitDecision: vi.fn(),
51
+ canConfirm: vi.fn().mockReturnValue(true),
63
52
  promptPermission: vi
64
53
  .fn()
65
54
  .mockResolvedValue({ approved: true, state: "approved" }),
66
- ...rest,
67
- } as unknown as HandlerDeps;
55
+ ...overrides,
56
+ };
68
57
  }
69
58
 
70
59
  // ── tests ──────────────────────────────────────────────────────────────────
@@ -72,8 +61,8 @@ function makeDeps(overrides: Record<string, unknown> = {}): HandlerDeps {
72
61
  describe("evaluateSkillReadGate", () => {
73
62
  it("returns null when tool is not read", async () => {
74
63
  const tcc = makeTcc({ toolName: "write" });
75
- const deps = makeDeps({
76
- runtime: { activeSkillEntries: [makeSkillEntry()] },
64
+ const deps = makeSkillReadGateDeps({
65
+ getActiveSkillEntries: vi.fn().mockReturnValue([makeSkillEntry()]),
77
66
  });
78
67
  const result = await evaluateSkillReadGate(tcc, deps);
79
68
  expect(result).toBeNull();
@@ -81,15 +70,17 @@ describe("evaluateSkillReadGate", () => {
81
70
 
82
71
  it("returns null when no active skill entries", async () => {
83
72
  const tcc = makeTcc();
84
- const deps = makeDeps({ runtime: { activeSkillEntries: [] } });
73
+ const deps = makeSkillReadGateDeps({
74
+ getActiveSkillEntries: vi.fn().mockReturnValue([]),
75
+ });
85
76
  const result = await evaluateSkillReadGate(tcc, deps);
86
77
  expect(result).toBeNull();
87
78
  });
88
79
 
89
80
  it("returns null when read path does not match any skill", async () => {
90
81
  const tcc = makeTcc({ input: { path: "/test/project/src/index.ts" } });
91
- const deps = makeDeps({
92
- runtime: { activeSkillEntries: [makeSkillEntry()] },
82
+ const deps = makeSkillReadGateDeps({
83
+ getActiveSkillEntries: vi.fn().mockReturnValue([makeSkillEntry()]),
93
84
  });
94
85
  const result = await evaluateSkillReadGate(tcc, deps);
95
86
  expect(result).toBeNull();
@@ -97,10 +88,10 @@ describe("evaluateSkillReadGate", () => {
97
88
 
98
89
  it("returns allow when skill state is allow", async () => {
99
90
  const tcc = makeTcc();
100
- const deps = makeDeps({
101
- runtime: {
102
- activeSkillEntries: [makeSkillEntry({ state: "allow" })],
103
- },
91
+ const deps = makeSkillReadGateDeps({
92
+ getActiveSkillEntries: vi
93
+ .fn()
94
+ .mockReturnValue([makeSkillEntry({ state: "allow" })]),
104
95
  });
105
96
  const result = await evaluateSkillReadGate(tcc, deps);
106
97
  expect(result).toEqual({ action: "allow" });
@@ -108,10 +99,10 @@ describe("evaluateSkillReadGate", () => {
108
99
 
109
100
  it("returns block when skill state is deny", async () => {
110
101
  const tcc = makeTcc();
111
- const deps = makeDeps({
112
- runtime: {
113
- activeSkillEntries: [makeSkillEntry({ state: "deny" })],
114
- },
102
+ const deps = makeSkillReadGateDeps({
103
+ getActiveSkillEntries: vi
104
+ .fn()
105
+ .mockReturnValue([makeSkillEntry({ state: "deny" })]),
115
106
  });
116
107
  const result = await evaluateSkillReadGate(tcc, deps);
117
108
  expect(result).toMatchObject({ action: "block" });
@@ -119,10 +110,10 @@ describe("evaluateSkillReadGate", () => {
119
110
 
120
111
  it("returns allow when state is ask and user approves", async () => {
121
112
  const tcc = makeTcc();
122
- const deps = makeDeps({
123
- runtime: {
124
- activeSkillEntries: [makeSkillEntry({ state: "ask" })],
125
- },
113
+ const deps = makeSkillReadGateDeps({
114
+ getActiveSkillEntries: vi
115
+ .fn()
116
+ .mockReturnValue([makeSkillEntry({ state: "ask" })]),
126
117
  promptPermission: vi
127
118
  .fn()
128
119
  .mockResolvedValue({ approved: true, state: "approved" }),
@@ -133,10 +124,10 @@ describe("evaluateSkillReadGate", () => {
133
124
 
134
125
  it("returns block when state is ask and user denies", async () => {
135
126
  const tcc = makeTcc();
136
- const deps = makeDeps({
137
- runtime: {
138
- activeSkillEntries: [makeSkillEntry({ state: "ask" })],
139
- },
127
+ const deps = makeSkillReadGateDeps({
128
+ getActiveSkillEntries: vi
129
+ .fn()
130
+ .mockReturnValue([makeSkillEntry({ state: "ask" })]),
140
131
  promptPermission: vi
141
132
  .fn()
142
133
  .mockResolvedValue({ approved: false, state: "denied" }),
@@ -147,28 +138,25 @@ describe("evaluateSkillReadGate", () => {
147
138
 
148
139
  it("returns block when state is ask and no UI available", async () => {
149
140
  const tcc = makeTcc();
150
- const deps = makeDeps({
151
- runtime: {
152
- activeSkillEntries: [makeSkillEntry({ state: "ask" })],
153
- },
154
- canRequestPermissionConfirmation: vi.fn().mockReturnValue(false),
141
+ const deps = makeSkillReadGateDeps({
142
+ getActiveSkillEntries: vi
143
+ .fn()
144
+ .mockReturnValue([makeSkillEntry({ state: "ask" })]),
145
+ canConfirm: vi.fn().mockReturnValue(false),
155
146
  });
156
147
  const result = await evaluateSkillReadGate(tcc, deps);
157
148
  expect(result).toMatchObject({ action: "block" });
158
149
  });
159
150
 
160
151
  it("emits decision event with correct fields on deny", async () => {
161
- const events = makeEvents();
162
152
  const tcc = makeTcc({ agentName: "test-agent" });
163
- const deps = makeDeps({
164
- runtime: {
165
- activeSkillEntries: [makeSkillEntry({ state: "deny" })],
166
- },
167
- events,
153
+ const deps = makeSkillReadGateDeps({
154
+ getActiveSkillEntries: vi
155
+ .fn()
156
+ .mockReturnValue([makeSkillEntry({ state: "deny" })]),
168
157
  });
169
158
  await evaluateSkillReadGate(tcc, deps);
170
- expect(events.emit).toHaveBeenCalledWith(
171
- "permissions:decision",
159
+ expect(deps.emitDecision).toHaveBeenCalledWith(
172
160
  expect.objectContaining({
173
161
  surface: "skill",
174
162
  value: "librarian",
@@ -182,17 +170,14 @@ describe("evaluateSkillReadGate", () => {
182
170
  });
183
171
 
184
172
  it("emits decision event with correct fields on allow", async () => {
185
- const events = makeEvents();
186
173
  const tcc = makeTcc();
187
- const deps = makeDeps({
188
- runtime: {
189
- activeSkillEntries: [makeSkillEntry({ state: "allow" })],
190
- },
191
- events,
174
+ const deps = makeSkillReadGateDeps({
175
+ getActiveSkillEntries: vi
176
+ .fn()
177
+ .mockReturnValue([makeSkillEntry({ state: "allow" })]),
192
178
  });
193
179
  await evaluateSkillReadGate(tcc, deps);
194
- expect(events.emit).toHaveBeenCalledWith(
195
- "permissions:decision",
180
+ expect(deps.emitDecision).toHaveBeenCalledWith(
196
181
  expect.objectContaining({
197
182
  surface: "skill",
198
183
  value: "librarian",