Skip to content

Commit 32a72ed

Browse files
committed
fixup! chore(eslint): enforce no-explicit-any with bulk suppressions for existing violations
1 parent 5c55169 commit 32a72ed

5 files changed

Lines changed: 158 additions & 100 deletions

File tree

src/__tests__/helpers/provider-stub.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,38 @@ import { ClineProvider } from "../../core/webview/ClineProvider"
22
import { TaskRegistry } from "../../core/task/TaskRegistry"
33
import { type Task } from "../../core/task/Task"
44

5+
type ProviderStubFields = {
6+
delegationTransitionLocks?: Map<string, Promise<void>>
7+
cancelledDelegationChildIds?: Set<string>
8+
log?: ReturnType<typeof vi.fn>
9+
taskHistoryStore?: { get: (id: string) => unknown }
10+
taskRegistry?: TaskRegistry
11+
clineStack?: Task[]
12+
tasks?: Task[]
13+
runDelegationTransition?: unknown
14+
removeClineFromStack?: unknown
15+
evictCurrentTask?: unknown
16+
}
17+
18+
type PrivateProviderMethods = {
19+
runDelegationTransition: (this: unknown, ...args: unknown[]) => unknown
20+
removeClineFromStack: (this: unknown, ...args: unknown[]) => unknown
21+
evictCurrentTask: (this: unknown, ...args: unknown[]) => unknown
22+
}
23+
524
/**
625
* Augments a plain stub object with the instance fields and bound methods that
726
* ClineProvider methods read from `this` (runDelegationTransition,
827
* delegationTransitionLocks, cancelledDelegationChildIds, cancellingDelegationChildIds),
9-
* so tests can call private methods via `(ClineProvider.prototype as any).method.call(stub, …)`
28+
* so tests can call private ClineProvider methods against a plain object
1029
* without instantiating a real ClineProvider.
1130
*
1231
* Pass `tasks` (array of Task mocks) to pre-seed the registry in stack order.
1332
* The legacy `clineStack` key is accepted and converted automatically.
1433
*/
1534
export function makeProviderStub<T extends object>(stub: T): ClineProvider {
16-
const s = stub as any
17-
const proto = ClineProvider.prototype as any
35+
const s = stub as T & ProviderStubFields
36+
const proto = ClineProvider.prototype as unknown as PrivateProviderMethods
1837
s.delegationTransitionLocks ??= new Map()
1938
s.cancelledDelegationChildIds ??= new Set()
2039
s.log ??= vi.fn()

src/__tests__/removeClineFromStack-delegation.spec.ts

Lines changed: 57 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,28 @@
11
// npx vitest run __tests__/removeClineFromStack-delegation.spec.ts
22

3-
import { describe, it, expect, vi } from "vitest"
3+
import { describe, it, expect, vi, type MockedFunction } from "vitest"
44
import { ClineProvider } from "../core/webview/ClineProvider"
55
import { TaskRegistry } from "../core/task/TaskRegistry"
6+
import { type Task } from "../core/task/Task"
67
import { makeProviderStub } from "./helpers/provider-stub"
78

9+
type MockTask = Pick<Task, "taskId" | "instanceId"> &
10+
Partial<Pick<Task, "parentTaskId" | "abort" | "abandoned">> & {
11+
emit: ReturnType<typeof vi.fn>
12+
abortTask: ReturnType<typeof vi.fn>
13+
}
14+
15+
type PrivateClineProviderMethods = {
16+
removeClineFromStack: (this: ClineProvider) => ReturnType<ClineProvider["removeClineFromStack"]>
17+
markDelegatedChildInterrupted: (
18+
this: ClineProvider,
19+
...args: Parameters<ClineProvider["markDelegatedChildInterrupted"]>
20+
) => ReturnType<ClineProvider["markDelegatedChildInterrupted"]>
21+
evictCurrentTask: (this: ClineProvider) => ReturnType<ClineProvider["evictCurrentTask"]>
22+
}
23+
24+
const privateClineProvider = ClineProvider.prototype as unknown as PrivateClineProviderMethods
25+
826
// After the refactor: removeClineFromStack() is pure lifecycle — it removes the focused task, aborts, and
927
// cleans up listeners. It does NOT mutate delegation metadata. All delegated→active
1028
// transitions are owned by reopenParentFromDelegation() (normal child completion) or
@@ -13,7 +31,7 @@ import { makeProviderStub } from "./helpers/provider-stub"
1331
function buildMockProvider(opts: {
1432
childTaskId: string
1533
parentTaskId?: string
16-
parentHistoryItem?: Record<string, any>
34+
parentHistoryItem?: Record<string, unknown>
1735
childStatus?: string
1836
}) {
1937
const childTask = {
@@ -32,13 +50,13 @@ function buildMockProvider(opts: {
3250
throw new Error("Task not found")
3351
})
3452

35-
const taskHistoryStoreData: Record<string, any> = {}
53+
const taskHistoryStoreData: Record<string, unknown> = {}
3654
if (opts.childStatus) {
3755
taskHistoryStoreData[opts.childTaskId] = { status: opts.childStatus }
3856
}
3957

4058
const provider = makeProviderStub({
41-
clineStack: [childTask] as any[],
59+
clineStack: [childTask] as unknown as Task[],
4260
taskEventListeners: new Map(),
4361
log: vi.fn(),
4462
getTaskWithId,
@@ -54,7 +72,7 @@ describe("ClineProvider.removeClineFromStack() — pure lifecycle, no delegation
5472
const { provider, childTask } = buildMockProvider({ childTaskId: "child-1" })
5573
expect(provider["taskRegistry"].length).toBe(1)
5674

57-
await (ClineProvider.prototype as any).removeClineFromStack.call(provider)
75+
await privateClineProvider.removeClineFromStack.call(provider)
5876

5977
expect(provider["taskRegistry"].length).toBe(0)
6078
expect(childTask.abortTask).toHaveBeenCalledWith(true)
@@ -75,15 +93,15 @@ describe("ClineProvider.removeClineFromStack() — pure lifecycle, no delegation
7593
abortTask: vi.fn().mockResolvedValue(undefined),
7694
}
7795
const provider = makeProviderStub({
78-
tasks: [focusedTask, topTask] as any[],
96+
tasks: [focusedTask, topTask] as unknown as Task[],
7997
taskEventListeners: new Map(),
8098
log: vi.fn(),
8199
getTaskWithId: vi.fn(),
82100
updateTaskHistory: vi.fn(),
83101
})
84102
provider["taskRegistry"].setCurrent("focused-1")
85103

86-
await (ClineProvider.prototype as any).removeClineFromStack.call(provider)
104+
await privateClineProvider.removeClineFromStack.call(provider)
87105

88106
expect(provider["taskRegistry"].taskIds).toEqual(["top-1"])
89107
expect(provider["taskRegistry"].current).toBe(topTask)
@@ -103,7 +121,7 @@ describe("ClineProvider.removeClineFromStack() — pure lifecycle, no delegation
103121
},
104122
})
105123

106-
await (ClineProvider.prototype as any).removeClineFromStack.call(provider)
124+
await privateClineProvider.removeClineFromStack.call(provider)
107125

108126
expect(provider["taskRegistry"].length).toBe(0)
109127
// Navigation/disposal must never silently flip the parent to active
@@ -123,7 +141,7 @@ describe("ClineProvider.removeClineFromStack() — pure lifecycle, no delegation
123141
childStatus: "interrupted",
124142
})
125143

126-
await (ClineProvider.prototype as any).removeClineFromStack.call(provider)
144+
await privateClineProvider.removeClineFromStack.call(provider)
127145

128146
expect(provider["taskRegistry"].length).toBe(0)
129147
expect(getTaskWithId).not.toHaveBeenCalled()
@@ -135,7 +153,7 @@ describe("ClineProvider.removeClineFromStack() — pure lifecycle, no delegation
135153
childTaskId: "standalone-1",
136154
})
137155

138-
await (ClineProvider.prototype as any).removeClineFromStack.call(provider)
156+
await privateClineProvider.removeClineFromStack.call(provider)
139157

140158
expect(provider["taskRegistry"].length).toBe(0)
141159
expect(getTaskWithId).not.toHaveBeenCalled()
@@ -144,14 +162,14 @@ describe("ClineProvider.removeClineFromStack() — pure lifecycle, no delegation
144162

145163
it("handles empty stack gracefully", async () => {
146164
const provider = makeProviderStub({
147-
clineStack: [] as any[],
165+
clineStack: [] as Task[],
148166
taskEventListeners: new Map(),
149167
log: vi.fn(),
150168
getTaskWithId: vi.fn(),
151169
updateTaskHistory: vi.fn(),
152170
})
153171

154-
await expect((ClineProvider.prototype as any).removeClineFromStack.call(provider)).resolves.not.toThrow()
172+
await expect(privateClineProvider.removeClineFromStack.call(provider)).resolves.not.toThrow()
155173

156174
expect(provider["getTaskWithId"]).not.toHaveBeenCalled()
157175
expect(provider["updateTaskHistory"]).not.toHaveBeenCalled()
@@ -190,7 +208,7 @@ describe("ClineProvider.markDelegatedChildInterrupted() — live eviction path",
190208
const postMessageToWebview = vi.fn().mockResolvedValue(undefined)
191209

192210
const provider = makeProviderStub({
193-
clineStack: [] as any[],
211+
clineStack: [] as Task[],
194212
taskEventListeners: new Map(),
195213
log: vi.fn(),
196214
getTaskWithId,
@@ -201,7 +219,7 @@ describe("ClineProvider.markDelegatedChildInterrupted() — live eviction path",
201219
},
202220
})
203221

204-
await (ClineProvider.prototype as any).markDelegatedChildInterrupted.call(provider, {
222+
await privateClineProvider.markDelegatedChildInterrupted.call(provider, {
205223
childTaskId,
206224
parentTaskId,
207225
})
@@ -234,7 +252,7 @@ describe("ClineProvider.markDelegatedChildInterrupted() — live eviction path",
234252
const updateTaskHistory = vi.fn().mockResolvedValue([])
235253

236254
const provider = makeProviderStub({
237-
clineStack: [] as any[],
255+
clineStack: [] as Task[],
238256
taskEventListeners: new Map(),
239257
log: vi.fn(),
240258
getTaskWithId: vi.fn(),
@@ -244,7 +262,7 @@ describe("ClineProvider.markDelegatedChildInterrupted() — live eviction path",
244262
},
245263
})
246264

247-
await (ClineProvider.prototype as any).markDelegatedChildInterrupted.call(provider, {
265+
await privateClineProvider.markDelegatedChildInterrupted.call(provider, {
248266
childTaskId,
249267
parentTaskId,
250268
})
@@ -266,7 +284,7 @@ describe("ClineProvider.markDelegatedChildInterrupted() — live eviction path",
266284
})
267285

268286
const provider = makeProviderStub({
269-
clineStack: [] as any[],
287+
clineStack: [] as Task[],
270288
taskEventListeners: new Map(),
271289
log: vi.fn(),
272290
getTaskWithId,
@@ -276,7 +294,7 @@ describe("ClineProvider.markDelegatedChildInterrupted() — live eviction path",
276294
},
277295
})
278296

279-
await (ClineProvider.prototype as any).markDelegatedChildInterrupted.call(provider, {
297+
await privateClineProvider.markDelegatedChildInterrupted.call(provider, {
280298
childTaskId,
281299
parentTaskId,
282300
})
@@ -305,7 +323,7 @@ describe("ClineProvider.markDelegatedChildInterrupted() — live eviction path",
305323
delegationTransitionLocks: new Map(),
306324
})
307325
const provider = makeProviderStub({
308-
clineStack: [] as any[],
326+
clineStack: [] as Task[],
309327
taskEventListeners: new Map(),
310328
log: vi.fn(),
311329
getTaskWithId,
@@ -330,7 +348,7 @@ describe("ClineProvider.markDelegatedChildInterrupted() — live eviction path",
330348
},
331349
})
332350

333-
await (ClineProvider.prototype as any).markDelegatedChildInterrupted.call(provider, {
351+
await privateClineProvider.markDelegatedChildInterrupted.call(provider, {
334352
childTaskId,
335353
parentTaskId,
336354
})
@@ -347,7 +365,7 @@ describe("ClineProvider.markDelegatedChildInterrupted() — live eviction path",
347365
const getTaskWithId = vi.fn().mockRejectedValue(new Error("store unavailable"))
348366

349367
const provider = makeProviderStub({
350-
clineStack: [] as any[],
368+
clineStack: [] as Task[],
351369
taskEventListeners: new Map(),
352370
log,
353371
getTaskWithId,
@@ -358,7 +376,7 @@ describe("ClineProvider.markDelegatedChildInterrupted() — live eviction path",
358376
})
359377

360378
await expect(
361-
(ClineProvider.prototype as any).markDelegatedChildInterrupted.call(provider, {
379+
privateClineProvider.markDelegatedChildInterrupted.call(provider, {
362380
childTaskId,
363381
parentTaskId,
364382
}),
@@ -406,7 +424,7 @@ describe("createTaskWithHistoryItem() navigation — does not mutate delegation
406424
const markDelegatedChildInterrupted = vi.fn().mockResolvedValue(undefined)
407425

408426
const provider = makeProviderStub({
409-
clineStack: [childTask] as any[],
427+
clineStack: [childTask] as unknown as Task[],
410428
taskEventListeners: new Map(),
411429
log: vi.fn(),
412430
getTaskWithId,
@@ -425,7 +443,7 @@ describe("createTaskWithHistoryItem() navigation — does not mutate delegation
425443
// Simulate the navigation logic from createTaskWithHistoryItem:
426444
// when the target is a delegated parent and current task is its interrupted child,
427445
// removeClineFromStack must NOT repair parent to active.
428-
await (ClineProvider.prototype as any).removeClineFromStack.call(provider)
446+
await privateClineProvider.removeClineFromStack.call(provider)
429447

430448
// Parent must stay delegated — no write at all
431449
expect(updateTaskHistory).not.toHaveBeenCalledWith(expect.objectContaining({ id: parentTaskId }))
@@ -460,7 +478,7 @@ describe("createTaskWithHistoryItem() navigation — does not mutate delegation
460478
const postMessageToWebview = vi.fn().mockResolvedValue(undefined)
461479

462480
const provider = makeProviderStub({
463-
clineStack: [] as any[],
481+
clineStack: [] as Task[],
464482
taskEventListeners: new Map(),
465483
log: vi.fn(),
466484
getTaskWithId,
@@ -476,7 +494,7 @@ describe("createTaskWithHistoryItem() navigation — does not mutate delegation
476494
},
477495
})
478496

479-
await (ClineProvider.prototype as any).markDelegatedChildInterrupted.call(provider, {
497+
await privateClineProvider.markDelegatedChildInterrupted.call(provider, {
480498
childTaskId,
481499
parentTaskId,
482500
})
@@ -512,15 +530,15 @@ describe("ClineProvider.evictCurrentTask() — active delegated child path", ()
512530
const markDelegatedChildInterrupted = vi.fn().mockResolvedValue(undefined)
513531

514532
const provider = makeProviderStub({
515-
clineStack: [childTask] as any[],
533+
clineStack: [childTask] as unknown as Task[],
516534
taskEventListeners: new Map(),
517535
getCurrentTask: vi.fn(() => childTask),
518536
taskHistoryStore: { get: vi.fn((id: string) => (id === childTaskId ? childHistoryItem : undefined)) },
519537
markDelegatedChildInterrupted,
520538
log: vi.fn(),
521539
})
522540

523-
await (ClineProvider.prototype as any).evictCurrentTask.call(provider)
541+
await privateClineProvider.evictCurrentTask.call(provider)
524542

525543
expect(provider["taskRegistry"].length).toBe(0)
526544
expect(markDelegatedChildInterrupted).toHaveBeenCalledWith({ childTaskId, parentTaskId })
@@ -530,15 +548,15 @@ describe("ClineProvider.evictCurrentTask() — active delegated child path", ()
530548
const markDelegatedChildInterrupted = vi.fn()
531549

532550
const provider = makeProviderStub({
533-
clineStack: [] as any[],
551+
clineStack: [] as Task[],
534552
taskEventListeners: new Map(),
535553
getCurrentTask: vi.fn(() => undefined),
536554
taskHistoryStore: { get: vi.fn(() => undefined) },
537555
markDelegatedChildInterrupted,
538556
log: vi.fn(),
539557
})
540558

541-
await (ClineProvider.prototype as any).evictCurrentTask.call(provider)
559+
await privateClineProvider.evictCurrentTask.call(provider)
542560

543561
expect(markDelegatedChildInterrupted).not.toHaveBeenCalled()
544562
})
@@ -554,7 +572,7 @@ describe("ClineProvider.evictCurrentTask() — active delegated child path", ()
554572
const markDelegatedChildInterrupted = vi.fn()
555573

556574
const provider = makeProviderStub({
557-
clineStack: [childTask] as any[],
575+
clineStack: [childTask] as unknown as Task[],
558576
taskEventListeners: new Map(),
559577
getCurrentTask: vi.fn(() => childTask),
560578
taskHistoryStore: {
@@ -564,7 +582,7 @@ describe("ClineProvider.evictCurrentTask() — active delegated child path", ()
564582
log: vi.fn(),
565583
})
566584

567-
await (ClineProvider.prototype as any).evictCurrentTask.call(provider)
585+
await privateClineProvider.evictCurrentTask.call(provider)
568586

569587
expect(markDelegatedChildInterrupted).not.toHaveBeenCalled()
570588
})
@@ -584,7 +602,7 @@ describe("ClineProvider.evictCurrentTask() — active delegated child path", ()
584602
const markDelegatedChildInterrupted = vi.fn().mockRejectedValue(new Error("lock contention"))
585603

586604
const provider = makeProviderStub({
587-
clineStack: [childTask] as any[],
605+
clineStack: [childTask] as unknown as Task[],
588606
taskEventListeners: new Map(),
589607
getCurrentTask: vi.fn(() => childTask),
590608
taskHistoryStore: {
@@ -594,14 +612,14 @@ describe("ClineProvider.evictCurrentTask() — active delegated child path", ()
594612
log: vi.fn(),
595613
})
596614

597-
await expect((ClineProvider.prototype as any).evictCurrentTask.call(provider)).rejects.toThrow(
598-
"lock contention",
599-
)
615+
await expect(privateClineProvider.evictCurrentTask.call(provider)).rejects.toThrow("lock contention")
600616
})
601617
})
602618

603619
describe("onTaskCompleted callback — writes completed status before re-emitting", () => {
604-
function buildCallbackProvider(taskHistoryStoreGet: (id: string) => any) {
620+
type CallbackHistoryItem = { id: string; status?: string; [key: string]: unknown }
621+
622+
function buildCallbackProvider(taskHistoryStoreGet: (id: string) => CallbackHistoryItem | undefined) {
605623
const updateTaskHistory = vi.fn().mockResolvedValue([])
606624
const emit = vi.fn()
607625
const log = vi.fn()
@@ -616,7 +634,7 @@ describe("onTaskCompleted callback — writes completed status before re-emittin
616634
listeners[event] = listeners[event] || []
617635
listeners[event].push(fn)
618636
}),
619-
emit: vi.fn((event: string, ...args: any[]) => {
637+
emit: vi.fn((event: string, ...args: unknown[]) => {
620638
listeners[event]?.forEach((fn) => fn(...args))
621639
}),
622640
}
@@ -692,7 +710,7 @@ describe("onTaskCompleted callback — writes completed status before re-emittin
692710
const { onTaskCompleted, updateTaskHistory, log } = buildCallbackProvider((id) =>
693711
id === "task-1" ? existingItem : undefined,
694712
)
695-
;(updateTaskHistory as any).mockRejectedValue(new Error("disk full"))
713+
vi.mocked(updateTaskHistory).mockRejectedValue(new Error("disk full"))
696714

697715
await expect(onTaskCompleted("task-1")).resolves.not.toThrow()
698716

0 commit comments

Comments
 (0)