@gotgenes/pi-permission-system 10.2.0 → 10.3.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.
@@ -5,9 +5,6 @@ const {
5
5
  mockLoggerDebug,
6
6
  mockLoggerReview,
7
7
  mockCreateLogger,
8
- mockLoadAndMergeConfigs,
9
- mockSyncPermissionSystemStatus,
10
- mockBuildResolvedConfigLogEntry,
11
8
  mockDiscoverGlobalNodeModulesRoot,
12
9
  } = vi.hoisted(() => ({
13
10
  mockLoggerDebug:
@@ -19,9 +16,6 @@ const {
19
16
  (event: string, details?: Record<string, unknown>) => string | undefined
20
17
  >(),
21
18
  mockCreateLogger: vi.fn(),
22
- mockLoadAndMergeConfigs: vi.fn(),
23
- mockSyncPermissionSystemStatus: vi.fn(),
24
- mockBuildResolvedConfigLogEntry: vi.fn(),
25
19
  mockDiscoverGlobalNodeModulesRoot: vi.fn<() => string | null>(),
26
20
  }));
27
21
 
@@ -33,21 +27,6 @@ vi.mock("../src/permission-manager", () => ({
33
27
  PermissionManager: vi.fn(),
34
28
  }));
35
29
 
36
- vi.mock("../src/config-loader", () => ({
37
- loadAndMergeConfigs: mockLoadAndMergeConfigs,
38
- loadUnifiedConfig: vi.fn().mockReturnValue({ config: {} }),
39
- }));
40
-
41
- vi.mock("../src/status", () => ({
42
- PERMISSION_SYSTEM_STATUS_KEY: "permission-system",
43
- syncPermissionSystemStatus: mockSyncPermissionSystemStatus,
44
- getPermissionSystemStatus: vi.fn(),
45
- }));
46
-
47
- vi.mock("../src/config-reporter", () => ({
48
- buildResolvedConfigLogEntry: mockBuildResolvedConfigLogEntry,
49
- }));
50
-
51
30
  vi.mock("../src/subagent-context", () => ({
52
31
  isSubagentExecutionContext: vi.fn().mockReturnValue(false),
53
32
  }));
@@ -61,10 +40,9 @@ vi.mock("../src/session-rules", () => ({
61
40
  deriveApprovalPattern: vi.fn(),
62
41
  }));
63
42
 
64
- import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
65
43
  import { getGlobalLogsDir } from "#src/config-paths";
66
44
  import { DEFAULT_EXTENSION_CONFIG } from "#src/extension-config";
67
- import { createExtensionRuntime, refreshExtensionConfig } from "#src/runtime";
45
+ import { createExtensionRuntime } from "#src/runtime";
68
46
 
69
47
  // ── test suite ─────────────────────────────────────────────────────────────
70
48
 
@@ -151,9 +129,9 @@ describe("createExtensionRuntime", () => {
151
129
 
152
130
  // ── Default mutable state ────────────────────────────────────────────────
153
131
 
154
- it("initializes config to DEFAULT_EXTENSION_CONFIG", () => {
132
+ it("initializes configStore.current() to DEFAULT_EXTENSION_CONFIG", () => {
155
133
  const runtime = createExtensionRuntime({ agentDir: "/test/agent" });
156
- expect(runtime.config).toEqual(DEFAULT_EXTENSION_CONFIG);
134
+ expect(runtime.configStore.current()).toEqual(DEFAULT_EXTENSION_CONFIG);
157
135
  });
158
136
 
159
137
  it("initializes runtimeContext to null", () => {
@@ -181,11 +159,6 @@ describe("createExtensionRuntime", () => {
181
159
  expect(runtime.lastPromptStateCacheKey).toBeNull();
182
160
  });
183
161
 
184
- it("initializes lastConfigWarning to null", () => {
185
- const runtime = createExtensionRuntime({ agentDir: "/test/agent" });
186
- expect(runtime.lastConfigWarning).toBeNull();
187
- });
188
-
189
162
  it("creates a sessionRules instance", () => {
190
163
  const runtime = createExtensionRuntime({ agentDir: "/test/agent" });
191
164
  expect(runtime.sessionRules).toBeDefined();
@@ -193,17 +166,6 @@ describe("createExtensionRuntime", () => {
193
166
 
194
167
  // ── Mutable state is writable ──────────────────────────────────────────
195
168
 
196
- it("allows config to be updated", () => {
197
- const runtime = createExtensionRuntime({ agentDir: "/test/agent" });
198
- const newConfig = {
199
- debugLog: true,
200
- permissionReviewLog: false,
201
- yoloMode: false,
202
- };
203
- runtime.config = newConfig;
204
- expect(runtime.config).toEqual(newConfig);
205
- });
206
-
207
169
  it("allows runtimeContext to be updated", () => {
208
170
  const runtime = createExtensionRuntime({ agentDir: "/test/agent" });
209
171
  const mockCtx = { hasUI: false } as never;
@@ -226,19 +188,13 @@ describe("createExtensionRuntime", () => {
226
188
  expect(opts.reviewLogPath).toContain(expectedLogsDir);
227
189
  });
228
190
 
229
- it("passes getConfig that reads current runtime.config", () => {
230
- const runtime = createExtensionRuntime({ agentDir: "/test/agent" });
191
+ it("passes getConfig that reads from configStore.current()", () => {
192
+ createExtensionRuntime({ agentDir: "/test/agent" });
231
193
  const opts = mockCreateLogger.mock.calls[0][0] as {
232
194
  getConfig: () => typeof DEFAULT_EXTENSION_CONFIG;
233
195
  };
234
- const updatedConfig = {
235
- debugLog: true,
236
- permissionReviewLog: false,
237
- yoloMode: false,
238
- };
239
- runtime.config = updatedConfig;
240
- // getConfig() should reflect the updated value
241
- expect(opts.getConfig()).toEqual(updatedConfig);
196
+ // getConfig() reads from configStore.current() — DEFAULT_EXTENSION_CONFIG at startup
197
+ expect(opts.getConfig()).toEqual(DEFAULT_EXTENSION_CONFIG);
242
198
  });
243
199
 
244
200
  // ── writeDebugLog delegates to logger.debug ──────────────────────────────
@@ -340,148 +296,8 @@ describe("createExtensionRuntime", () => {
340
296
  });
341
297
  });
342
298
 
343
- // ── refreshExtensionConfig ────────────────────────────────────────────────
344
-
345
- describe("refreshExtensionConfig", () => {
346
- function makeRuntime() {
347
- mockCreateLogger.mockReturnValue({
348
- debug: mockLoggerDebug,
349
- review: mockLoggerReview,
350
- });
351
- return createExtensionRuntime({ agentDir: "/test/agent" });
352
- }
353
-
354
- function makeCtx(
355
- overrides: Partial<ExtensionContext> = {},
356
- ): ExtensionContext {
357
- return {
358
- cwd: "/test/project",
359
- hasUI: false,
360
- ui: { notify: vi.fn(), setStatus: vi.fn() },
361
- sessionManager: { getEntries: vi.fn(), addEntry: vi.fn() },
362
- ...overrides,
363
- } as unknown as ExtensionContext;
364
- }
365
-
366
- beforeEach(() => {
367
- mockLoggerDebug.mockReset().mockReturnValue(undefined);
368
- mockLoggerReview.mockReset().mockReturnValue(undefined);
369
- mockLoadAndMergeConfigs.mockReset().mockReturnValue({
370
- merged: { ...DEFAULT_EXTENSION_CONFIG },
371
- issues: [],
372
- });
373
- mockSyncPermissionSystemStatus.mockReset();
374
- });
375
-
376
- it("updates runtime.runtimeContext when ctx is provided", () => {
377
- const runtime = makeRuntime();
378
- const ctx = makeCtx();
379
- refreshExtensionConfig(runtime, ctx);
380
- expect(runtime.runtimeContext).toBe(ctx);
381
- });
382
-
383
- it("does not override runtimeContext when ctx is omitted", () => {
384
- const runtime = makeRuntime();
385
- const existing = makeCtx();
386
- runtime.runtimeContext = existing;
387
- refreshExtensionConfig(runtime);
388
- expect(runtime.runtimeContext).toBe(existing);
389
- });
390
-
391
- it("updates runtime.config with normalized merged result", () => {
392
- const runtime = makeRuntime();
393
- mockLoadAndMergeConfigs.mockReturnValue({
394
- merged: { debugLog: true, permissionReviewLog: false, yoloMode: false },
395
- issues: [],
396
- });
397
- refreshExtensionConfig(runtime);
398
- expect(runtime.config.debugLog).toBe(true);
399
- expect(runtime.config.permissionReviewLog).toBe(false);
400
- });
401
-
402
- it("calls loadAndMergeConfigs with runtime.agentDir and cwd", () => {
403
- const runtime = makeRuntime();
404
- const ctx = makeCtx({ cwd: "/my/project" });
405
- refreshExtensionConfig(runtime, ctx);
406
- expect(mockLoadAndMergeConfigs).toHaveBeenCalledWith(
407
- "/test/agent",
408
- "/my/project",
409
- expect.any(String), // EXTENSION_ROOT
410
- );
411
- });
412
-
413
- it("writes config.loaded debug log", () => {
414
- const runtime = makeRuntime();
415
- refreshExtensionConfig(runtime);
416
- expect(mockLoggerDebug).toHaveBeenCalledWith(
417
- "config.loaded",
418
- expect.objectContaining({ debugLog: false }),
419
- );
420
- });
421
-
422
- it("sets lastConfigWarning when issues are present", () => {
423
- const runtime = makeRuntime();
424
- mockLoadAndMergeConfigs.mockReturnValue({
425
- merged: { ...DEFAULT_EXTENSION_CONFIG },
426
- issues: ["legacy config detected"],
427
- });
428
- refreshExtensionConfig(runtime);
429
- expect(runtime.lastConfigWarning).toBe("legacy config detected");
430
- });
431
-
432
- it("clears lastConfigWarning when no issues", () => {
433
- const runtime = makeRuntime();
434
- runtime.lastConfigWarning = "old warning";
435
- mockLoadAndMergeConfigs.mockReturnValue({
436
- merged: { ...DEFAULT_EXTENSION_CONFIG },
437
- issues: [],
438
- });
439
- refreshExtensionConfig(runtime);
440
- expect(runtime.lastConfigWarning).toBeNull();
441
- });
442
-
443
- it("notifies UI when a new warning appears and hasUI is true", () => {
444
- const runtime = makeRuntime();
445
- const mockNotify = vi.fn();
446
- const ctx = makeCtx({ hasUI: true, ui: { notify: mockNotify } as never });
447
- mockLoadAndMergeConfigs.mockReturnValue({
448
- merged: { ...DEFAULT_EXTENSION_CONFIG },
449
- issues: ["new warning"],
450
- });
451
- refreshExtensionConfig(runtime, ctx);
452
- expect(mockNotify).toHaveBeenCalledWith("new warning", "warning");
453
- });
454
-
455
- it("does not re-notify the same warning on subsequent calls", () => {
456
- const runtime = makeRuntime();
457
- const mockNotify = vi.fn();
458
- const ctx = makeCtx({ hasUI: true, ui: { notify: mockNotify } as never });
459
- mockLoadAndMergeConfigs.mockReturnValue({
460
- merged: { ...DEFAULT_EXTENSION_CONFIG },
461
- issues: ["persistent warning"],
462
- });
463
- refreshExtensionConfig(runtime, ctx);
464
- refreshExtensionConfig(runtime, ctx);
465
- expect(mockNotify).toHaveBeenCalledTimes(1);
466
- });
467
-
468
- it("calls syncPermissionSystemStatus when hasUI is true", () => {
469
- const runtime = makeRuntime();
470
- const ctx = makeCtx({ hasUI: true });
471
- refreshExtensionConfig(runtime, ctx);
472
- expect(mockSyncPermissionSystemStatus).toHaveBeenCalledWith(
473
- ctx,
474
- expect.any(Object),
475
- );
476
- });
477
-
478
- it("does not call syncPermissionSystemStatus when hasUI is false", () => {
479
- const runtime = makeRuntime();
480
- const ctx = makeCtx({ hasUI: false });
481
- refreshExtensionConfig(runtime, ctx);
482
- expect(mockSyncPermissionSystemStatus).not.toHaveBeenCalled();
483
- });
484
- });
299
+ // refreshExtensionConfig / saveExtensionConfig / logResolvedConfigPaths are
300
+ // thin delegators to runtime.configStore — behavior covered in config-store.test.ts.
485
301
 
486
302
  // resolveAgentName was moved to PermissionSession (#129)
487
- // Tests live in tests/permission-session.test.ts
303
+ // Tests live in test/permission-session.test.ts