@gotgenes/pi-permission-system 5.9.0 → 5.11.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 +30 -0
- package/package.json +1 -1
- package/src/forwarding-manager.ts +1 -1
- package/src/handlers/before-agent-start.ts +76 -76
- package/src/handlers/gates/descriptor.ts +1 -1
- package/src/handlers/index.ts +6 -15
- package/src/handlers/lifecycle.ts +55 -59
- package/src/handlers/permission-gate-handler.ts +346 -0
- package/src/index.ts +46 -54
- package/src/permission-prompter.ts +23 -6
- package/src/permission-session.ts +281 -0
- package/src/runtime.ts +5 -30
- package/src/session-logger.ts +1 -1
- package/src/skill-prompt-sanitizer.ts +15 -4
- package/src/tool-registry.ts +6 -0
- package/tests/handlers/before-agent-start.test.ts +116 -167
- package/tests/handlers/input-events.test.ts +87 -92
- package/tests/handlers/input.test.ts +98 -128
- package/tests/handlers/lifecycle.test.ts +97 -227
- package/tests/handlers/tool-call-events.test.ts +146 -166
- package/tests/handlers/tool-call.test.ts +102 -97
- package/tests/permission-prompter.test.ts +1 -1
- package/tests/permission-session.test.ts +607 -0
- package/tests/runtime.test.ts +2 -77
- package/src/handlers/input.ts +0 -126
- package/src/handlers/tool-call.ts +0 -210
- package/src/handlers/types.ts +0 -90
|
@@ -1,29 +1,9 @@
|
|
|
1
1
|
import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
handleSessionShutdown,
|
|
6
|
-
handleSessionStart,
|
|
7
|
-
} from "../../src/handlers/lifecycle";
|
|
8
|
-
import type { HandlerDeps } from "../../src/handlers/types";
|
|
9
|
-
import type { PermissionManager } from "../../src/permission-manager";
|
|
10
|
-
import type { SessionState } from "../../src/runtime";
|
|
11
|
-
import type { SessionRules } from "../../src/session-rules";
|
|
12
|
-
import type { SkillPromptEntry } from "../../src/skill-prompt-sanitizer";
|
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { SessionLifecycleHandler } from "../../src/handlers/lifecycle";
|
|
4
|
+
import type { PermissionSession } from "../../src/permission-session";
|
|
13
5
|
|
|
14
|
-
// ──
|
|
15
|
-
const { mockGetActiveAgentName } = vi.hoisted(() => ({
|
|
16
|
-
mockGetActiveAgentName: vi.fn<(ctx: ExtensionContext) => string | null>(),
|
|
17
|
-
}));
|
|
18
|
-
|
|
19
|
-
vi.mock("../../src/active-agent", () => ({
|
|
20
|
-
getActiveAgentName: mockGetActiveAgentName,
|
|
21
|
-
getActiveAgentNameFromSystemPrompt: vi.fn().mockReturnValue(null),
|
|
22
|
-
}));
|
|
23
|
-
|
|
24
|
-
// ── PERMISSION_SYSTEM_STATUS_KEY stub ──────────────────────────────────────
|
|
25
|
-
// status.ts is re-exported through the handler; the key value doesn't matter
|
|
26
|
-
// for these tests.
|
|
6
|
+
// ── status stub ────────────────────────────────────────────────────────────
|
|
27
7
|
vi.mock("../../src/status", () => ({
|
|
28
8
|
PERMISSION_SYSTEM_STATUS_KEY: "permission-system",
|
|
29
9
|
syncPermissionSystemStatus: vi.fn(),
|
|
@@ -51,156 +31,86 @@ function makeCtx(overrides: Partial<ExtensionContext> = {}): ExtensionContext {
|
|
|
51
31
|
} as unknown as ExtensionContext;
|
|
52
32
|
}
|
|
53
33
|
|
|
54
|
-
function
|
|
55
|
-
|
|
56
|
-
):
|
|
57
|
-
return {
|
|
58
|
-
getConfigIssues: vi.fn().mockReturnValue(issues),
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function makeSessionRules(): SessionRules {
|
|
63
|
-
return {
|
|
64
|
-
approve: vi.fn(),
|
|
65
|
-
getRuleset: vi.fn().mockReturnValue([]),
|
|
66
|
-
clear: vi.fn(),
|
|
67
|
-
} as unknown as SessionRules;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function makeSession(overrides: Partial<SessionState> = {}): SessionState {
|
|
71
|
-
return {
|
|
72
|
-
runtimeContext: null,
|
|
73
|
-
permissionManager: makePermissionManager() as unknown as PermissionManager,
|
|
74
|
-
activeSkillEntries: [] as SkillPromptEntry[],
|
|
75
|
-
lastKnownActiveAgentName: null,
|
|
76
|
-
lastActiveToolsCacheKey: null,
|
|
77
|
-
lastPromptStateCacheKey: null,
|
|
78
|
-
sessionRules: makeSessionRules(),
|
|
79
|
-
...overrides,
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function makeDeps(overrides: Partial<HandlerDeps> = {}): HandlerDeps {
|
|
34
|
+
function makeSession(
|
|
35
|
+
overrides: Partial<Record<keyof PermissionSession, unknown>> = {},
|
|
36
|
+
): PermissionSession {
|
|
84
37
|
return {
|
|
85
|
-
session: makeSession(),
|
|
86
38
|
logger: { debug: vi.fn(), review: vi.fn(), warn: vi.fn() },
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
createPermissionManagerForCwd: vi
|
|
90
|
-
.fn()
|
|
91
|
-
.mockReturnValue(makePermissionManager()),
|
|
92
|
-
refreshExtensionConfig: vi.fn(),
|
|
39
|
+
refreshConfig: vi.fn(),
|
|
40
|
+
resetForNewSession: vi.fn(),
|
|
93
41
|
logResolvedConfigPaths: vi.fn(),
|
|
94
42
|
resolveAgentName: vi.fn().mockReturnValue(null),
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
createPermissionRequestId: vi.fn().mockReturnValue("test-id"),
|
|
100
|
-
events: { emit: vi.fn(), on: vi.fn().mockReturnValue(() => undefined) },
|
|
101
|
-
forwarding: { start: vi.fn(), stop: vi.fn() },
|
|
102
|
-
stopPermissionRpcHandlers: vi.fn(),
|
|
103
|
-
getAllTools: vi.fn().mockReturnValue([]),
|
|
104
|
-
setActiveTools: vi.fn(),
|
|
43
|
+
getConfigIssues: vi.fn().mockReturnValue([]),
|
|
44
|
+
reload: vi.fn(),
|
|
45
|
+
getRuntimeContext: vi.fn().mockReturnValue(null),
|
|
46
|
+
shutdown: vi.fn(),
|
|
105
47
|
...overrides,
|
|
106
|
-
};
|
|
48
|
+
} as unknown as PermissionSession;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function makeHandler(
|
|
52
|
+
overrides?: Partial<Record<keyof PermissionSession, unknown>>,
|
|
53
|
+
): {
|
|
54
|
+
handler: SessionLifecycleHandler;
|
|
55
|
+
session: PermissionSession;
|
|
56
|
+
cleanupRpc: ReturnType<typeof vi.fn>;
|
|
57
|
+
} {
|
|
58
|
+
const session = makeSession(overrides);
|
|
59
|
+
const cleanupRpc = vi.fn();
|
|
60
|
+
const handler = new SessionLifecycleHandler(session, cleanupRpc);
|
|
61
|
+
return { handler, session, cleanupRpc };
|
|
107
62
|
}
|
|
108
63
|
|
|
109
64
|
// ── handleSessionStart ─────────────────────────────────────────────────────
|
|
110
65
|
|
|
111
66
|
describe("handleSessionStart", () => {
|
|
112
|
-
|
|
113
|
-
mockGetActiveAgentName.mockReset();
|
|
114
|
-
mockGetActiveAgentName.mockReturnValue(null);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it("sets the runtime context", async () => {
|
|
118
|
-
const ctx = makeCtx();
|
|
119
|
-
const deps = makeDeps();
|
|
120
|
-
await handleSessionStart(deps, { reason: "startup" }, ctx);
|
|
121
|
-
expect(deps.session.runtimeContext).toBe(ctx);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it("refreshes extension config with ctx", async () => {
|
|
125
|
-
const ctx = makeCtx();
|
|
126
|
-
const deps = makeDeps();
|
|
127
|
-
await handleSessionStart(deps, { reason: "startup" }, ctx);
|
|
128
|
-
expect(deps.refreshExtensionConfig).toHaveBeenCalledWith(ctx);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it("creates a new permission manager for ctx.cwd and stores it", async () => {
|
|
132
|
-
const ctx = makeCtx({ cwd: "/my/project" });
|
|
133
|
-
const newPm = makePermissionManager();
|
|
134
|
-
const deps = makeDeps({
|
|
135
|
-
createPermissionManagerForCwd: vi.fn().mockReturnValue(newPm),
|
|
136
|
-
});
|
|
137
|
-
await handleSessionStart(deps, { reason: "startup" }, ctx);
|
|
138
|
-
expect(deps.createPermissionManagerForCwd).toHaveBeenCalledWith(
|
|
139
|
-
"/my/project",
|
|
140
|
-
);
|
|
141
|
-
expect(deps.session.permissionManager).toBe(newPm);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it("clears the before_agent_start cache", async () => {
|
|
145
|
-
const ctx = makeCtx();
|
|
146
|
-
const deps = makeDeps();
|
|
147
|
-
await handleSessionStart(deps, { reason: "startup" }, ctx);
|
|
148
|
-
expect(deps.session.activeSkillEntries).toEqual([]);
|
|
149
|
-
expect(deps.session.lastActiveToolsCacheKey).toBeNull();
|
|
150
|
-
expect(deps.session.lastPromptStateCacheKey).toBeNull();
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
it("sets lastKnownActiveAgentName from getActiveAgentName", async () => {
|
|
154
|
-
mockGetActiveAgentName.mockReturnValue("my-agent");
|
|
67
|
+
it("refreshes config with ctx", async () => {
|
|
155
68
|
const ctx = makeCtx();
|
|
156
|
-
const
|
|
157
|
-
await handleSessionStart(
|
|
158
|
-
expect(
|
|
69
|
+
const { handler, session } = makeHandler();
|
|
70
|
+
await handler.handleSessionStart({ reason: "startup" }, ctx);
|
|
71
|
+
expect(session.refreshConfig).toHaveBeenCalledWith(ctx);
|
|
159
72
|
});
|
|
160
73
|
|
|
161
|
-
it("
|
|
162
|
-
mockGetActiveAgentName.mockReturnValue(null);
|
|
74
|
+
it("calls resetForNewSession with ctx", async () => {
|
|
163
75
|
const ctx = makeCtx();
|
|
164
|
-
const
|
|
165
|
-
await handleSessionStart(
|
|
166
|
-
expect(
|
|
76
|
+
const { handler, session } = makeHandler();
|
|
77
|
+
await handler.handleSessionStart({ reason: "startup" }, ctx);
|
|
78
|
+
expect(session.resetForNewSession).toHaveBeenCalledWith(ctx);
|
|
167
79
|
});
|
|
168
80
|
|
|
169
|
-
it("
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
expect(deps.forwarding.start).toHaveBeenCalledWith(ctx);
|
|
81
|
+
it("logs resolved config paths", async () => {
|
|
82
|
+
const { handler, session } = makeHandler();
|
|
83
|
+
await handler.handleSessionStart({ reason: "startup" }, makeCtx());
|
|
84
|
+
expect(session.logResolvedConfigPaths).toHaveBeenCalledOnce();
|
|
174
85
|
});
|
|
175
86
|
|
|
176
|
-
it("
|
|
87
|
+
it("resolves agent name from ctx", async () => {
|
|
177
88
|
const ctx = makeCtx();
|
|
178
|
-
const
|
|
179
|
-
await handleSessionStart(
|
|
180
|
-
expect(
|
|
89
|
+
const { handler, session } = makeHandler();
|
|
90
|
+
await handler.handleSessionStart({ reason: "startup" }, ctx);
|
|
91
|
+
expect(session.resolveAgentName).toHaveBeenCalledWith(ctx);
|
|
181
92
|
});
|
|
182
93
|
|
|
183
94
|
it("notifies each policy issue", async () => {
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
createPermissionManagerForCwd: vi.fn().mockReturnValue(pm),
|
|
95
|
+
const { handler, session } = makeHandler({
|
|
96
|
+
getConfigIssues: vi.fn().mockReturnValue(["issue A", "issue B"]),
|
|
187
97
|
});
|
|
188
|
-
await handleSessionStart(
|
|
189
|
-
expect(
|
|
190
|
-
expect(
|
|
98
|
+
await handler.handleSessionStart({ reason: "startup" }, makeCtx());
|
|
99
|
+
expect(session.logger.warn).toHaveBeenCalledWith("issue A");
|
|
100
|
+
expect(session.logger.warn).toHaveBeenCalledWith("issue B");
|
|
191
101
|
});
|
|
192
102
|
|
|
193
|
-
it("does not
|
|
194
|
-
const
|
|
195
|
-
await handleSessionStart(
|
|
196
|
-
expect(
|
|
103
|
+
it("does not warn when there are no policy issues", async () => {
|
|
104
|
+
const { handler, session } = makeHandler();
|
|
105
|
+
await handler.handleSessionStart({ reason: "startup" }, makeCtx());
|
|
106
|
+
expect(session.logger.warn).not.toHaveBeenCalled();
|
|
197
107
|
});
|
|
198
108
|
|
|
199
109
|
it("writes lifecycle.reload debug log when reason is reload", async () => {
|
|
200
110
|
const ctx = makeCtx({ cwd: "/proj" });
|
|
201
|
-
const
|
|
202
|
-
await handleSessionStart(
|
|
203
|
-
expect(
|
|
111
|
+
const { handler, session } = makeHandler();
|
|
112
|
+
await handler.handleSessionStart({ reason: "reload" }, ctx);
|
|
113
|
+
expect(session.logger.debug).toHaveBeenCalledWith("lifecycle.reload", {
|
|
204
114
|
triggeredBy: "session_start",
|
|
205
115
|
reason: "reload",
|
|
206
116
|
cwd: "/proj",
|
|
@@ -208,9 +118,19 @@ describe("handleSessionStart", () => {
|
|
|
208
118
|
});
|
|
209
119
|
|
|
210
120
|
it("does not write lifecycle.reload debug log for non-reload reasons", async () => {
|
|
211
|
-
const
|
|
212
|
-
await handleSessionStart(
|
|
213
|
-
expect(
|
|
121
|
+
const { handler, session } = makeHandler();
|
|
122
|
+
await handler.handleSessionStart({ reason: "startup" }, makeCtx());
|
|
123
|
+
expect(session.logger.debug).not.toHaveBeenCalled();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("calls refreshConfig before resetForNewSession", async () => {
|
|
127
|
+
const callOrder: string[] = [];
|
|
128
|
+
const { handler } = makeHandler({
|
|
129
|
+
refreshConfig: vi.fn(() => callOrder.push("refreshConfig")),
|
|
130
|
+
resetForNewSession: vi.fn(() => callOrder.push("resetForNewSession")),
|
|
131
|
+
});
|
|
132
|
+
await handler.handleSessionStart({ reason: "startup" }, makeCtx());
|
|
133
|
+
expect(callOrder).toEqual(["refreshConfig", "resetForNewSession"]);
|
|
214
134
|
});
|
|
215
135
|
});
|
|
216
136
|
|
|
@@ -218,45 +138,24 @@ describe("handleSessionStart", () => {
|
|
|
218
138
|
|
|
219
139
|
describe("handleResourcesDiscover", () => {
|
|
220
140
|
it("does nothing when reason is not reload", async () => {
|
|
221
|
-
const
|
|
222
|
-
await handleResourcesDiscover(
|
|
223
|
-
expect(
|
|
224
|
-
expect(deps.logger.debug).not.toHaveBeenCalled();
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
it("creates and stores a new PM using runtimeContext.cwd on reload", async () => {
|
|
228
|
-
const ctx = makeCtx({ cwd: "/runtime/cwd" });
|
|
229
|
-
const newPm = makePermissionManager();
|
|
230
|
-
const deps = makeDeps({
|
|
231
|
-
session: makeSession({ runtimeContext: ctx }),
|
|
232
|
-
createPermissionManagerForCwd: vi.fn().mockReturnValue(newPm),
|
|
233
|
-
});
|
|
234
|
-
await handleResourcesDiscover(deps, { reason: "reload" });
|
|
235
|
-
expect(deps.createPermissionManagerForCwd).toHaveBeenCalledWith(
|
|
236
|
-
"/runtime/cwd",
|
|
237
|
-
);
|
|
238
|
-
expect(deps.session.permissionManager).toBe(newPm);
|
|
141
|
+
const { handler, session } = makeHandler();
|
|
142
|
+
await handler.handleResourcesDiscover({ reason: "startup" });
|
|
143
|
+
expect(session.reload).not.toHaveBeenCalled();
|
|
239
144
|
});
|
|
240
145
|
|
|
241
|
-
it("
|
|
242
|
-
const
|
|
243
|
-
await handleResourcesDiscover(
|
|
244
|
-
expect(
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
it("clears the before_agent_start cache on reload", async () => {
|
|
248
|
-
const deps = makeDeps();
|
|
249
|
-
await handleResourcesDiscover(deps, { reason: "reload" });
|
|
250
|
-
expect(deps.session.activeSkillEntries).toEqual([]);
|
|
251
|
-
expect(deps.session.lastActiveToolsCacheKey).toBeNull();
|
|
252
|
-
expect(deps.session.lastPromptStateCacheKey).toBeNull();
|
|
146
|
+
it("calls reload on the session on reload", async () => {
|
|
147
|
+
const { handler, session } = makeHandler();
|
|
148
|
+
await handler.handleResourcesDiscover({ reason: "reload" });
|
|
149
|
+
expect(session.reload).toHaveBeenCalledOnce();
|
|
253
150
|
});
|
|
254
151
|
|
|
255
152
|
it("writes lifecycle.reload debug log on reload", async () => {
|
|
256
153
|
const ctx = makeCtx({ cwd: "/proj" });
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
154
|
+
const { handler, session } = makeHandler({
|
|
155
|
+
getRuntimeContext: vi.fn().mockReturnValue(ctx),
|
|
156
|
+
});
|
|
157
|
+
await handler.handleResourcesDiscover({ reason: "reload" });
|
|
158
|
+
expect(session.logger.debug).toHaveBeenCalledWith("lifecycle.reload", {
|
|
260
159
|
triggeredBy: "resources_discover",
|
|
261
160
|
reason: "reload",
|
|
262
161
|
cwd: "/proj",
|
|
@@ -264,9 +163,9 @@ describe("handleResourcesDiscover", () => {
|
|
|
264
163
|
});
|
|
265
164
|
|
|
266
165
|
it("logs cwd as null when runtimeContext is null on reload", async () => {
|
|
267
|
-
const
|
|
268
|
-
await handleResourcesDiscover(
|
|
269
|
-
expect(
|
|
166
|
+
const { handler, session } = makeHandler();
|
|
167
|
+
await handler.handleResourcesDiscover({ reason: "reload" });
|
|
168
|
+
expect(session.logger.debug).toHaveBeenCalledWith("lifecycle.reload", {
|
|
270
169
|
triggeredBy: "resources_discover",
|
|
271
170
|
reason: "reload",
|
|
272
171
|
cwd: null,
|
|
@@ -277,12 +176,12 @@ describe("handleResourcesDiscover", () => {
|
|
|
277
176
|
// ── handleSessionShutdown ──────────────────────────────────────────────────
|
|
278
177
|
|
|
279
178
|
describe("handleSessionShutdown", () => {
|
|
280
|
-
it("clears
|
|
179
|
+
it("clears UI status when runtime context is present", async () => {
|
|
281
180
|
const ctx = makeCtx();
|
|
282
|
-
const
|
|
283
|
-
|
|
181
|
+
const { handler } = makeHandler({
|
|
182
|
+
getRuntimeContext: vi.fn().mockReturnValue(ctx),
|
|
284
183
|
});
|
|
285
|
-
await handleSessionShutdown(
|
|
184
|
+
await handler.handleSessionShutdown();
|
|
286
185
|
expect(ctx.ui.setStatus).toHaveBeenCalledWith(
|
|
287
186
|
"permission-system",
|
|
288
187
|
undefined,
|
|
@@ -290,48 +189,19 @@ describe("handleSessionShutdown", () => {
|
|
|
290
189
|
});
|
|
291
190
|
|
|
292
191
|
it("does not throw when runtime context is null", async () => {
|
|
293
|
-
const
|
|
294
|
-
await expect(handleSessionShutdown(
|
|
192
|
+
const { handler } = makeHandler();
|
|
193
|
+
await expect(handler.handleSessionShutdown()).resolves.not.toThrow();
|
|
295
194
|
});
|
|
296
195
|
|
|
297
|
-
it("
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
expect(deps.session.runtimeContext).toBeNull();
|
|
196
|
+
it("calls shutdown on the session", async () => {
|
|
197
|
+
const { handler, session } = makeHandler();
|
|
198
|
+
await handler.handleSessionShutdown();
|
|
199
|
+
expect(session.shutdown).toHaveBeenCalledOnce();
|
|
302
200
|
});
|
|
303
201
|
|
|
304
|
-
it("
|
|
305
|
-
const
|
|
306
|
-
await handleSessionShutdown(
|
|
307
|
-
expect(
|
|
308
|
-
expect(deps.session.lastActiveToolsCacheKey).toBeNull();
|
|
309
|
-
expect(deps.session.lastPromptStateCacheKey).toBeNull();
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
it("clears the session rules", async () => {
|
|
313
|
-
const deps = makeDeps();
|
|
314
|
-
await handleSessionShutdown(deps);
|
|
315
|
-
expect(deps.session.sessionRules.clear).toHaveBeenCalledOnce();
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
it("stops forwarded permission polling", async () => {
|
|
319
|
-
const deps = makeDeps();
|
|
320
|
-
await handleSessionShutdown(deps);
|
|
321
|
-
expect(deps.forwarding.stop).toHaveBeenCalledOnce();
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
it("calls stopPermissionRpcHandlers on shutdown", async () => {
|
|
325
|
-
const deps = makeDeps();
|
|
326
|
-
await handleSessionShutdown(deps);
|
|
327
|
-
expect(deps.stopPermissionRpcHandlers).toHaveBeenCalledOnce();
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
it("does not reset lastKnownActiveAgentName", async () => {
|
|
331
|
-
const deps = makeDeps({
|
|
332
|
-
session: makeSession({ lastKnownActiveAgentName: "remembered" }),
|
|
333
|
-
});
|
|
334
|
-
await handleSessionShutdown(deps);
|
|
335
|
-
expect(deps.session.lastKnownActiveAgentName).toBe("remembered");
|
|
202
|
+
it("calls cleanupRpc", async () => {
|
|
203
|
+
const { handler, cleanupRpc } = makeHandler();
|
|
204
|
+
await handler.handleSessionShutdown();
|
|
205
|
+
expect(cleanupRpc).toHaveBeenCalledOnce();
|
|
336
206
|
});
|
|
337
207
|
});
|