Merge remote-tracking branch 'origin/master' into codex/experimental-plugin-group-note
This commit is contained in:
@@ -601,7 +601,7 @@ function backscanGoal(log: readonly SessionEvent[]): FxGoalProjection | null {
|
||||
const source = event.data?.source
|
||||
if (source?.kind !== 'goal' || source.round !== 0) continue
|
||||
const change = source.change
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-condition
|
||||
if (change === undefined || change.kind !== 'goal/change') continue
|
||||
if (change.operation === 'clear') return null
|
||||
return { goal: change.goal, roundsStarted: change.roundsStarted, createdAt: change.createdAt, updatedAt: change.updatedAt }
|
||||
|
||||
@@ -32,7 +32,7 @@ const install: InvariantInstaller = (ctx, fail) => {
|
||||
const baselines = new WeakMap<Fiber, number>()
|
||||
// Async listener by design: emitPluginDisposed awaits-and-logs returned
|
||||
// promises, so a violation surfaces loudly instead of unhandled.
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
// oxlint-disable-next-line typescript/no-misused-promises
|
||||
ctx.on('internal/plugin', async (fiber) => {
|
||||
if (fiber.name !== 'client-hmr') return
|
||||
if (fiber.uid !== null) {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* with the last holding entry, session instances cleared (with persisted
|
||||
* state) on scope death.
|
||||
*/
|
||||
/* eslint-disable @typescript-eslint/no-redundant-type-constituents --
|
||||
/* oxlint-disable typescript/no-redundant-type-constituents --
|
||||
* `keyof SlotMap & string` is the declare-merge key pattern: SlotMap only
|
||||
* holds this package's 'root' row in this compilation unit, but consumers
|
||||
* merge keys in; the rule fires on the narrow-map view, not on real
|
||||
@@ -310,6 +310,6 @@ export class SlotsService extends Service {
|
||||
// The core's overloads proved the shares; the implementation works on
|
||||
// the erased view (same pattern as the core's own implementation arm).
|
||||
const options = rawOptions as ErasedRegisterOptions
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity
|
||||
// oxlint-disable-next-line typescript/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity
|
||||
return this.ctx.effect(() => this['_register'](options, component), 'slots.register()')
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/* jscpd:ignore-start */
|
||||
/* eslint-disable @typescript-eslint/no-redundant-type-constituents --
|
||||
/* oxlint-disable typescript/no-redundant-type-constituents --
|
||||
* `keyof SlotMap & string` is the declare-merge key pattern: SlotMap is empty
|
||||
* in this compilation unit (intersection reads `never`) but consumers merge
|
||||
* keys in; the rule fires on the empty-map view, not on real redundancy. */
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* machinery — everything mounts the production implementations.
|
||||
* @module @deepseek-ai/dsh-client-test-runtime
|
||||
*/
|
||||
/* eslint-disable @typescript-eslint/no-redundant-type-constituents --
|
||||
/* oxlint-disable typescript/no-redundant-type-constituents --
|
||||
* `keyof SlotMap & string` is the declare-merge key pattern (see ui-slots):
|
||||
* this compilation unit sees only the runtime's 'root' row, but consumer
|
||||
* programs merge their own keys in; the rule fires on the narrow-map view. */
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
export async function writeClipboard(text: string): Promise<void> {
|
||||
// lib.dom types clipboard non-optional, but insecure contexts omit it —
|
||||
// that runtime gap is exactly what this guard detects.
|
||||
/* eslint-disable-next-line @typescript-eslint/no-unnecessary-condition */
|
||||
/* oxlint-disable-next-line typescript/no-unnecessary-condition */
|
||||
if (navigator.clipboard?.writeText) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text)
|
||||
@@ -19,7 +19,7 @@ export async function writeClipboard(text: string): Promise<void> {
|
||||
}
|
||||
// execCommand('copy') is the only clipboard fallback where the async API
|
||||
// is missing (insecure contexts); deprecated but deliberately retained.
|
||||
/* eslint-disable @typescript-eslint/no-deprecated */
|
||||
/* oxlint-disable typescript/no-deprecated */
|
||||
const exec = typeof document.execCommand === 'function'
|
||||
? document.execCommand.bind(document)
|
||||
: undefined
|
||||
@@ -36,7 +36,7 @@ export async function writeClipboard(text: string): Promise<void> {
|
||||
} catch {
|
||||
// Clipboard unavailable; the button stays idle.
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/no-deprecated */
|
||||
/* oxlint-enable typescript/no-deprecated */
|
||||
el.remove()
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ export function InputBar({
|
||||
// IME guard so a composition-closing Shift+Enter still breaks the line.
|
||||
if (e.key === 'Enter' && e.shiftKey) return
|
||||
// keyCode 229 is the legacy IME-composition signal engines emit without isComposing.
|
||||
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
||||
// oxlint-disable-next-line typescript/no-deprecated
|
||||
const composing = composingRef.current || e.nativeEvent.isComposing || e.nativeEvent.keyCode === 229
|
||||
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
||||
if (keyboard.arbitrate(e.key === 'ArrowUp' ? 'up' : 'down', composing) === 'consumed') e.preventDefault()
|
||||
@@ -165,8 +165,8 @@ export function InputBar({
|
||||
if (machineBusy) return // submitting is the read-only span; adjudicating holds the pending lock
|
||||
const next = e.target.value
|
||||
keyboard.setDraft(next)
|
||||
// selectionStart is number|null in lib.dom; the eslint program narrows it.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
// selectionStart is number|null in lib.dom; the type-aware lint program narrows it.
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-condition
|
||||
keyboard.track(next, e.target.selectionStart ?? next.length)
|
||||
}
|
||||
|
||||
@@ -178,13 +178,13 @@ export function InputBar({
|
||||
// too (one char = one step). Mouse selection of a chip is handled in the
|
||||
// backdrop click handler below. Undo/redo must NOT reach the browser: the
|
||||
// machine owns the transaction log.
|
||||
// selectionStart/End are number|null in lib.dom; the eslint program narrows them.
|
||||
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
||||
// selectionStart/End are number|null in lib.dom; the type-aware lint program narrows them.
|
||||
/* oxlint-disable typescript/no-unnecessary-condition */
|
||||
const selectionOf = (el: HTMLTextAreaElement) => ({
|
||||
start: el.selectionStart ?? 0,
|
||||
end: el.selectionEnd ?? el.selectionStart ?? 0,
|
||||
})
|
||||
/* eslint-enable @typescript-eslint/no-unnecessary-condition */
|
||||
/* oxlint-enable typescript/no-unnecessary-condition */
|
||||
|
||||
const onCopyOrCut = (e: React.ClipboardEvent<HTMLTextAreaElement>, cut: boolean): void => {
|
||||
const el = e.currentTarget
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
export async function writeClipboard(text: string): Promise<boolean> {
|
||||
// lib.dom types clipboard non-optional, but insecure contexts omit it —
|
||||
// that runtime gap is exactly what this guard detects.
|
||||
/* eslint-disable-next-line @typescript-eslint/no-unnecessary-condition */
|
||||
/* oxlint-disable-next-line typescript/no-unnecessary-condition */
|
||||
if (navigator.clipboard?.writeText) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text)
|
||||
@@ -25,7 +25,7 @@ export async function writeClipboard(text: string): Promise<boolean> {
|
||||
// jsdom and older hosts: best-effort execCommand path when present.
|
||||
// execCommand('copy') is the only clipboard fallback where the async API
|
||||
// is missing; deprecated but deliberately retained.
|
||||
/* eslint-disable @typescript-eslint/no-deprecated */
|
||||
/* oxlint-disable typescript/no-deprecated */
|
||||
const exec = typeof document.execCommand === 'function'
|
||||
? document.execCommand.bind(document)
|
||||
: undefined
|
||||
@@ -44,5 +44,5 @@ export async function writeClipboard(text: string): Promise<boolean> {
|
||||
} finally {
|
||||
el.remove()
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/no-deprecated */
|
||||
/* oxlint-enable typescript/no-deprecated */
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ export function JsonBlock({ label, payload, defaultOpen = false }: {
|
||||
let s: string
|
||||
try {
|
||||
// lib typing hides stringify's undefined arm (undefined/function/symbol payloads).
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-condition
|
||||
s = JSON.stringify(payload, null, 2) ?? String(payload)
|
||||
} catch {
|
||||
s = String(payload)
|
||||
|
||||
@@ -38,7 +38,7 @@ export function parseQuestionTitle(title: string): string {
|
||||
/** Return whether a textarea key event belongs to an active IME composition. */
|
||||
function isComposing(event: KeyboardEvent<HTMLTextAreaElement>): boolean {
|
||||
// keyCode 229 is the legacy IME-composition signal engines emit without isComposing.
|
||||
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
||||
// oxlint-disable-next-line typescript/no-deprecated
|
||||
return event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229
|
||||
}
|
||||
|
||||
@@ -64,9 +64,9 @@ function QuestionFlow({ pending }: { pending: PendingQuestion }) {
|
||||
const [busy, setBusy] = useState<'answer' | 'cancel' | null>(null)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
// index stays in bounds (every setIndex site clamps) and drafts mirrors questions 1:1.
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
const question = questions[index]!
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
const draft = drafts[index]!
|
||||
const hasOptions = (question.options?.length ?? 0) > 0
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* consumer `declare module` augmentation merges with declarations lexically in
|
||||
* the augmented module, not with re-exports.
|
||||
*/
|
||||
/* eslint-disable @typescript-eslint/no-redundant-type-constituents --
|
||||
/* oxlint-disable typescript/no-redundant-type-constituents --
|
||||
* `keyof SlotMap & string` is the declare-merge key pattern: SlotMap is empty
|
||||
* in THIS compilation unit (so the intersection reads as `never`), but every
|
||||
* consumer merges keys in and the intersection is what keeps them string-typed.
|
||||
@@ -350,7 +350,7 @@ interface ErasedOptions {
|
||||
priority?: number | undefined
|
||||
children?: Record<string, SlotSpec<SlotEntryDef>> | undefined
|
||||
store?: StoreDecl | undefined
|
||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any --
|
||||
/* oxlint-disable-next-line typescript/no-explicit-any --
|
||||
* implementation-signature position only (both public overloads type inject
|
||||
* exactly); `never[]` would fail overload-to-implementation compatibility
|
||||
* against the per-declaration InjectParams tuples. */
|
||||
|
||||
@@ -21,7 +21,7 @@ export type MaybeSnapshotSelectorHook<T> =
|
||||
* declared as the store's complete write set (the audit face — components can
|
||||
* only write through these).
|
||||
*/
|
||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any --
|
||||
/* oxlint-disable-next-line typescript/no-explicit-any --
|
||||
* any[] (not unknown[]): each action carries its own parameter list, and
|
||||
* unknown[] would reject every concrete signature under strict parameter
|
||||
* contravariance. Params are re-inferred per action by BakedActions. */
|
||||
@@ -95,14 +95,14 @@ export interface StoreHandle<T, A extends ActionsDecl<T>> {
|
||||
* Exclusive-store registration form: the registrant passes the factory itself
|
||||
* and the framework calls it per entry x scope (no shared identity exists).
|
||||
*/
|
||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any --
|
||||
/* oxlint-disable-next-line typescript/no-explicit-any --
|
||||
* erased position accepting every StoreHandle instantiation; T/A are
|
||||
* recovered per use site by conditional inference (HandleOf/BoundActions/
|
||||
* PropsStore). */
|
||||
export type StoreFactory = () => StoreHandle<any, any>
|
||||
|
||||
/** The register `store` option position: a shared handle or an exclusive factory. */
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- same erased-constraint position as StoreFactory (see above).
|
||||
// oxlint-disable-next-line typescript/no-explicit-any -- same erased-constraint position as StoreFactory (see above).
|
||||
export type StoreDecl = StoreHandle<any, any> | StoreFactory
|
||||
|
||||
/** Normalize a store declaration to its handle type (factories yield their return). */
|
||||
|
||||
@@ -41,7 +41,7 @@ describe('tsdown client artifact', () => {
|
||||
// Same execution form the loader uses (inline script eval, window scope) —
|
||||
// the implied-eval ban targets accidental string execution, not this
|
||||
// deliberate bundle-execution fixture.
|
||||
// eslint-disable-next-line @typescript-eslint/no-implied-eval, @typescript-eslint/no-unsafe-call
|
||||
// oxlint-disable-next-line typescript/no-implied-eval, typescript/no-unsafe-call
|
||||
new Function(code!)()
|
||||
expect(handoff).toBeDefined()
|
||||
const modules = new Map<string, unknown>([
|
||||
|
||||
@@ -134,7 +134,7 @@ export function makeConsoleShim(logs: LogBuffer): Record<(typeof CONSOLE_LEVELS)
|
||||
export function captureStreamWrites(logs: LogBuffer, stream: PatchableStream): () => void {
|
||||
// The slot's VALUE is stored for restore and reassigned — never invoked
|
||||
// detached, so the unbound-method concern does not apply.
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
// oxlint-disable-next-line typescript/unbound-method
|
||||
const original = stream.write
|
||||
stream.write = (chunk: unknown, ...rest: unknown[]): boolean => {
|
||||
logs.push(typeof chunk === 'string' ? chunk : String(chunk))
|
||||
|
||||
@@ -195,7 +195,7 @@ export class BasicCompactService extends CompactService {
|
||||
// A model-free prune can land before later summary work fails. That
|
||||
// durable reduction is sufficient retry proof; do not discard it just
|
||||
// because the optional second phase threw. Cancellation still wins.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- the signal can abort while recovery is awaited.
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-condition -- the signal can abort while recovery is awaited.
|
||||
if (!signal.aborted && agent.session.surface.replaceGeneration > generation) {
|
||||
ctx.logger.warn(
|
||||
`context-overflow compaction failed after durable surface progress: ${message}; `
|
||||
@@ -205,14 +205,14 @@ export class BasicCompactService extends CompactService {
|
||||
return { kind: 'retry' }
|
||||
}
|
||||
ctx.logger.warn(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- the signal can abort while recovery is awaited.
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-condition -- the signal can abort while recovery is awaited.
|
||||
`context-overflow compaction failed: ${message}; ${signal.aborted
|
||||
? 'cancellation prevents retry'
|
||||
: 'preserving the original request error'}`,
|
||||
)
|
||||
return next()
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- the signal can abort while compaction is awaited.
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-condition -- the signal can abort while compaction is awaited.
|
||||
if (signal.aborted
|
||||
|| agent.session.surface.replaceGeneration <= generation) return next()
|
||||
if (result !== null) logResult(result, 'context overflow recovery')
|
||||
|
||||
@@ -49,7 +49,7 @@ export function selectCompactableRange(
|
||||
let accumulated = 0
|
||||
let keepFromIdx = pricedNodes.length
|
||||
for (let index = pricedNodes.length - 1; index >= 0; index -= 1) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
accumulated += pricedNodes[index]!.tokens
|
||||
keepFromIdx = index
|
||||
if (accumulated >= retainTokens) break
|
||||
@@ -57,15 +57,15 @@ export function selectCompactableRange(
|
||||
if (keepFromIdx === 0) return null
|
||||
|
||||
while (keepFromIdx > 0) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
if (toolPairingBalancedBefore(session, surfaceNodes[keepFromIdx]!)) break
|
||||
keepFromIdx -= 1
|
||||
}
|
||||
if (keepFromIdx === 0) return null
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
const first = surfaceNodes[0]!
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
const cutoff = surfaceNodes[keepFromIdx - 1]!
|
||||
return { start: first, end: cutoff }
|
||||
}
|
||||
@@ -98,11 +98,11 @@ export async function compactSurfaceRegion(
|
||||
`compactRegion: start seq ${start} (position ${startIdx}) is after end seq ${end} (position ${endIdx}) on the surface`,
|
||||
)
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
if (!toolPairingBalancedBefore(session, nodes[startIdx]!)) {
|
||||
throw new Error(`compactRegion: start seq ${start} is not a balanced boundary (would split a step's tool-call/result pair)`)
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
if (!toolPairingBalancedAfter(session, nodes[endIdx]!)) {
|
||||
throw new Error(`compactRegion: end seq ${end} is not a balanced boundary (would split a step, or the step is still open)`)
|
||||
}
|
||||
@@ -196,7 +196,7 @@ function buildSummarizationInput(
|
||||
const events = session.events
|
||||
const regionMessages = shadowedSeqs
|
||||
// shadowedSeqs are current surface seqs, so each is a valid log index.
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
.map(seq => session.deriveEventMessage(events[seq]!))
|
||||
.filter((message): message is Message => message !== null)
|
||||
return {
|
||||
@@ -213,7 +213,7 @@ function inspectTurnTail(
|
||||
let compactionInProgress = false
|
||||
let compactionStateKnown = false
|
||||
for (let index = events.length - 1; index >= 0; index -= 1) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
const event = events[index]!
|
||||
if (!compactionStateKnown) {
|
||||
if (event.type === 'compact/start') {
|
||||
|
||||
@@ -221,7 +221,7 @@ export class ReactLoopAgent implements Agent {
|
||||
if (this.abort !== undefined || !this.queued.some(item => item.wakeup)) return
|
||||
// The some() guard above proves the queue is non-empty; the non-null
|
||||
// assertion expresses that invariant.
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
const { message } = this.queued.shift()!
|
||||
const inheritedOutboxLength = this.outbox.length
|
||||
|
||||
@@ -368,7 +368,7 @@ export class ReactLoopAgent implements Agent {
|
||||
outcome.failure, requestFailureHistory, outcome.retryPolicy, signal,
|
||||
() => Promise.resolve<RequestErrorAction>(undefined),
|
||||
)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- signal can abort while recovery is awaited.
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-condition -- signal can abort while recovery is awaited.
|
||||
if (action?.kind === 'retry' && !signal.aborted) {
|
||||
retryFailures = Object.freeze([...requestFailureHistory, outcome.failure])
|
||||
}
|
||||
@@ -584,7 +584,7 @@ export class ReactLoopAgent implements Agent {
|
||||
const maxTokens = this.options.maxTokens
|
||||
const seedConfig = deepFreeze(structuredClone(
|
||||
this.requestHeaderLogged
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- the instance logged the header it now folds
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion -- the instance logged the header it now folds
|
||||
? persistedConfig!
|
||||
: {
|
||||
...route,
|
||||
|
||||
@@ -83,7 +83,7 @@ export async function executeToolCalls(
|
||||
let concluded = false
|
||||
while (next < planned.length) {
|
||||
// Commit before classifying again so registry changes affect unstarted calls.
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- bounded by the loop condition
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion -- bounded by the loop condition
|
||||
const first = planned[next]!
|
||||
const mode = ctx.tools.executionMode(first.exec).kind
|
||||
const group = mode === 'parallel' ? planned.slice(next) : [first]
|
||||
@@ -151,7 +151,7 @@ async function runGroup(
|
||||
const result = slot.needsPost
|
||||
? await ctx.tools[TOOL_REGISTRY_SCHEDULER].finalize(slot.exec, slot.result)
|
||||
: ctx.tools[TOOL_REGISTRY_SCHEDULER].finish(slot.exec, slot.result)
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- bounded index
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion -- bounded index
|
||||
appendToolResult(session, turn, step, call!.block, result, callSeqs[committed]!)
|
||||
for (const context of result.additionalContexts ?? []) acceptContext(context)
|
||||
concluded ||= result.concludesTurn === true
|
||||
@@ -162,7 +162,7 @@ async function runGroup(
|
||||
const inFlight = new Map<number, Promise<number>>()
|
||||
|
||||
const startCall = async (index: number): Promise<void> => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- bounded index
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion -- bounded index
|
||||
const call = group[index]!
|
||||
callSeqs[index] = appendToolCall(session, turn, step, call.block)
|
||||
started++
|
||||
@@ -198,7 +198,7 @@ async function runGroup(
|
||||
const fillPool = async (): Promise<void> => {
|
||||
while (!aborted && nextToStart < group.length && inFlight.size < maxParallelToolCalls) {
|
||||
// Re-read later modes after ordered commits so registry changes can create a barrier.
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- bounded by the loop condition
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion -- bounded by the loop condition
|
||||
const nextCall = group[nextToStart]!
|
||||
if (nextToStart > 0 && mode === 'parallel'
|
||||
&& ctx.tools.executionMode(nextCall.exec).kind !== 'parallel') break
|
||||
|
||||
@@ -249,7 +249,7 @@ describe('config-driven session id', () => {
|
||||
const failures: unknown[] = []
|
||||
ctx.on('agent-loop/config-start-failed', () => { throw unrenderable })
|
||||
// Deliberately violate the normal Error-only rejection rule to exercise the unknown boundary.
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
|
||||
// oxlint-disable-next-line typescript/prefer-promise-reject-errors
|
||||
ctx.on('agent-loop/config-start-failed', () => Promise.reject(unrenderable) as never)
|
||||
ctx.on('agent-loop/config-start-failed', (_sessionId, error) => { failures.push(error) })
|
||||
vi.spyOn(ctx.sessionPersistence, 'list').mockRejectedValue(unrenderable)
|
||||
|
||||
@@ -108,12 +108,12 @@ export function agentEvents(ctx: Context, agent: Agent): AgentEventDispatch {
|
||||
}
|
||||
},
|
||||
async serial(name, ...rest) {
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method -- the events mixin accessor returns a pre-bound function
|
||||
// oxlint-disable-next-line typescript/unbound-method -- the events mixin accessor returns a pre-bound function
|
||||
const serial = ctx.serial as (thisArg: Scoped<Agent>, name: string, ...args: unknown[]) => Promise<never>
|
||||
return await serial(carrier, name, agent, ...rest)
|
||||
},
|
||||
waterfall(name, ...rest) {
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method -- the events mixin accessor returns a pre-bound function
|
||||
// oxlint-disable-next-line typescript/unbound-method -- the events mixin accessor returns a pre-bound function
|
||||
const waterfall = ctx.waterfall as (thisArg: Scoped<Agent>, name: string, ...args: unknown[]) => never
|
||||
return waterfall(carrier, name, agent, ...rest)
|
||||
},
|
||||
|
||||
@@ -328,7 +328,7 @@ export class AgentRegistry extends Service {
|
||||
// caller's composite effect can yield it for in-order teardown; the
|
||||
// loop's constructor effect returns it directly, identity-nesting the
|
||||
// registration under that effect.
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity
|
||||
// oxlint-disable-next-line typescript/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity
|
||||
return dispose
|
||||
}
|
||||
|
||||
@@ -355,7 +355,7 @@ export class AgentRegistry extends Service {
|
||||
// capability and need no Cordis tracker magic.
|
||||
const { target } = this.requireFactory()
|
||||
const receiver = getTraceable(ownerCtx, target)
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method -- Reflect.apply intentionally supplies the caller-traced receiver
|
||||
// oxlint-disable-next-line typescript/unbound-method -- Reflect.apply intentionally supplies the caller-traced receiver
|
||||
return Reflect.apply(target.createAgent, receiver, [ownerCtx, options])
|
||||
}
|
||||
|
||||
@@ -370,7 +370,7 @@ export class AgentRegistry extends Service {
|
||||
const ownerCtx = this.ctx
|
||||
const { target } = this.requireFactory()
|
||||
const receiver = getTraceable(ownerCtx, target)
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method -- Reflect.apply intentionally supplies the caller-traced receiver
|
||||
// oxlint-disable-next-line typescript/unbound-method -- Reflect.apply intentionally supplies the caller-traced receiver
|
||||
return Reflect.apply(target.resume, receiver, [ownerCtx, options])
|
||||
}
|
||||
|
||||
@@ -397,7 +397,7 @@ export class AgentRegistry extends Service {
|
||||
yield this.enter(agent, this.ctx.agent)
|
||||
this.announce(agent)
|
||||
}.bind(this), 'agents.register()')
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity
|
||||
// oxlint-disable-next-line typescript/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity
|
||||
return dispose
|
||||
}
|
||||
|
||||
|
||||
@@ -241,7 +241,7 @@ export class ScopedLayers<L extends ScopeLayer> {
|
||||
}
|
||||
if (notify) this.onChange()
|
||||
}.bind(this), options.label)
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- exact synchronous disposer preserves Cordis effect identity
|
||||
// oxlint-disable-next-line typescript/no-misused-promises -- exact synchronous disposer preserves Cordis effect identity
|
||||
return dispose
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,7 +597,7 @@ export class Session {
|
||||
for (const seq of nodes.slice(this.derivedNodes)) {
|
||||
// Surface sequences are built from this.log — seq is always a valid
|
||||
// index by construction. The non-null assertion expresses that invariant.
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
const msg = this.deriveEventMessage(this.log[seq]!)
|
||||
// A surface node is one of the five message-producing types, but an
|
||||
// empty-content assistant/message (a max-tokens step that hosts only
|
||||
@@ -912,7 +912,7 @@ export class SessionStore extends Service {
|
||||
} catch (error: unknown) {
|
||||
// Preserve the listener's exact rejection value; flush is a caller-owned
|
||||
// failure boundary, and Cordis listeners may throw arbitrary values.
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
|
||||
// oxlint-disable-next-line typescript/prefer-promise-reject-errors
|
||||
return Promise.reject(error)
|
||||
}
|
||||
}))
|
||||
|
||||
@@ -340,7 +340,7 @@ export class SurfaceManager implements SessionSurface {
|
||||
/** Fold events appended since the previous access. */
|
||||
private _processDelta(): void {
|
||||
for (let i = this._lastProcessedSeq + 1; i < this.log.length; i++) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- bounded by the loop condition
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion -- bounded by the loop condition
|
||||
applySurfaceEvent(this._state, this.log[i]!, i, this.log)
|
||||
this._lastProcessedSeq = i
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ describe('packChunkRuns', () => {
|
||||
['a block-index switch', [...deltaRun('text-delta', 2), ...deltaRun('text-delta', 1, 2, 7)]],
|
||||
['a step switch', deltaRun('text-delta', 3).map((e, k) => k === 2 ? chunkEvent(e.seq, e.time, (e.data as { chunk: StreamChunk }).chunk, 1, 2) : e)],
|
||||
])('breaks a run on %s (both halves too short to pack)', (_label, events) => {
|
||||
expect(packChunkRuns(events as SessionEvent[])).toStrictEqual(events)
|
||||
expect(packChunkRuns(events)).toStrictEqual(events)
|
||||
})
|
||||
|
||||
it('breaks a tool-call run on call-id or name change', () => {
|
||||
|
||||
@@ -546,19 +546,19 @@ export function defineTool<const S extends ParameterSchemaSpec, const O extends
|
||||
options: DefineToolOptions<S, O>,
|
||||
): ToolDefinition {
|
||||
// Object-literal methods do not use `this`; retaining references is safe.
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
// oxlint-disable-next-line typescript/unbound-method
|
||||
const userExecute = options.execute
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
// oxlint-disable-next-line typescript/unbound-method
|
||||
const userFinalizeContent = options.finalizeContent
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
// oxlint-disable-next-line typescript/unbound-method
|
||||
const userRender = options.output.render
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
// oxlint-disable-next-line typescript/unbound-method
|
||||
const userPresentationMeta = options.output.presentationMeta
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
// oxlint-disable-next-line typescript/unbound-method
|
||||
const userPresentCall = options.presentCall
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
// oxlint-disable-next-line typescript/unbound-method
|
||||
const userPresentResult = options.presentResult
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
// oxlint-disable-next-line typescript/unbound-method
|
||||
const userIsConcurrencySafe = options.isConcurrencySafe
|
||||
if (options.timeoutMs !== undefined && (!Number.isFinite(options.timeoutMs) || options.timeoutMs <= 0)) {
|
||||
throw new Error(`defineTool(${options.name}): timeoutMs must be a positive finite number`)
|
||||
|
||||
@@ -27,7 +27,7 @@ export type ContentToolFixtureOptions<S extends ParameterSchemaSpec> = Omit<
|
||||
export function defineContentToolFixture<const S extends ParameterSchemaSpec>(
|
||||
options: ContentToolFixtureOptions<S>,
|
||||
): ToolDefinition {
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
// oxlint-disable-next-line typescript/unbound-method
|
||||
const execute = options.execute
|
||||
return defineTool({
|
||||
...options,
|
||||
|
||||
@@ -148,7 +148,7 @@ export function parseCliArgs(args: readonly string[]): CliCommand {
|
||||
throw new CliArgumentError(`expected exactly one positional task or -p, received ${parsed.positionals.length} positional(s)`)
|
||||
}
|
||||
// Cardinality was checked above, so the fallback index zero exists.
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
const task = prompt ?? parsed.positionals[0]!
|
||||
if (task.trim().length === 0) throw new CliArgumentError('task must not be blank')
|
||||
|
||||
@@ -301,7 +301,7 @@ export async function runOneShot(ctx: Context, options: OneShotOptions): Promise
|
||||
|
||||
try {
|
||||
/* v8 ignore next -- skips send only when cancellation wins the listener-registration race above */
|
||||
if (!firstTurnEnded) { // eslint-disable-line @typescript-eslint/no-unnecessary-condition
|
||||
if (!firstTurnEnded) { // oxlint-disable-line typescript/no-unnecessary-condition
|
||||
agent.followup(createUserMessage({ content: [{ type: 'text', text: options.task }], source: { kind: 'user' } }))
|
||||
}
|
||||
await turnEnded
|
||||
@@ -361,7 +361,7 @@ async function bootInterruptibly(
|
||||
return await Promise.race([booting, interruptedBoot])
|
||||
} catch (error: unknown) {
|
||||
// The awaited race permits the signal to change after the preflight check.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-condition
|
||||
if (signal.aborted) {
|
||||
void booting.then(
|
||||
async (lateContext) => {
|
||||
|
||||
@@ -32,6 +32,9 @@ class ObservedStateGate {
|
||||
* the write/edit prior-observation policy.
|
||||
*/
|
||||
private owner(actor: object | undefined): object | undefined {
|
||||
// tsgolint treats object as assignable to weak FsPolicyExec, while tsc still requires the structural cast for property access.
|
||||
// See the analyzer-divergence consequence in .agents/notes/implemented/process/2026-07-29-oxlint-linter.md.
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-type-assertion -- The analyzers disagree on this weak type.
|
||||
return (actor as FsPolicyExec | undefined)?.agent?.session
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ export function applyGoalProjection(state: GoalProjection | null, event: Session
|
||||
// Session-log data is a durable boundary: the static type promises the kind,
|
||||
// but a foreign or corrupted change record must degrade to same-reference,
|
||||
// never feed the zod parse in the registry drive.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- durable-boundary guard
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-condition -- durable-boundary guard
|
||||
if (change === undefined || change.kind !== 'goal/change') return state
|
||||
if (change.operation === 'clear') return null
|
||||
return {
|
||||
|
||||
@@ -23,7 +23,7 @@ export class GoalError extends HarnessError {
|
||||
* @param code - stable machine-routable classification.
|
||||
*/
|
||||
// Keep the constructor to narrow HarnessError's string code at this boundary.
|
||||
// eslint-disable-next-line @typescript-eslint/no-useless-constructor -- type-only narrowing
|
||||
// oxlint-disable-next-line typescript/no-useless-constructor -- type-only narrowing
|
||||
constructor(message: string, code: GoalErrorCode) {
|
||||
super(message, code)
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ function fullResponse(narrow: RpcResponse<unknown>): Response {
|
||||
*/
|
||||
// K appears once in the signature but ties the UNARY_ROUTES[K] row lookup to its own
|
||||
// schema/invoke pairing; a union parameter degrades the row to an uninvokable intersection.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-type-parameters
|
||||
async function handleUnary<K extends keyof RpcMethodMap>(
|
||||
api: ApiProxy, method: K, message: ClientRequest, signal: AbortSignal,
|
||||
): Promise<Response> {
|
||||
|
||||
@@ -78,14 +78,14 @@ export function boundedInsert(window: ListingCandidate[], candidate: ListingCand
|
||||
// oversized level costs O(1) per candidate past the head instead of a
|
||||
// window scan (100k children against a 1,001 window must not approach
|
||||
// 10^8 comparisons).
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- a full window (length === keep >= 1) has a tail
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion -- a full window (length === keep >= 1) has a tail
|
||||
if (window.length === keep && candidate.name.localeCompare(window[window.length - 1]!.name) >= 0) return true
|
||||
// Binary insertion keeps a retained candidate at O(log keep) comparisons.
|
||||
let lo = 0
|
||||
let hi = window.length
|
||||
while (lo < hi) {
|
||||
const mid = (lo + hi) >>> 1
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- bounded by the loop condition
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion -- bounded by the loop condition
|
||||
if (candidate.name.localeCompare(window[mid]!.name) < 0) hi = mid
|
||||
else lo = mid + 1
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ export function providerForClosedStep(
|
||||
if (stepEndIndex < 0) return undefined
|
||||
for (let index = stepEndIndex; index >= 0; index -= 1) {
|
||||
// The loop bounds prove this indexed read exists.
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
const event = events[index]!
|
||||
if (event.type === 'request/header') return event.data.header.config.provider
|
||||
}
|
||||
|
||||
@@ -531,7 +531,7 @@ export class LlmService extends Service {
|
||||
yield value
|
||||
}
|
||||
} finally {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- the iteration catch sets its latch before entering finally.
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-condition -- the iteration catch sets its latch before entering finally.
|
||||
if (!completed && !iterationFailed) {
|
||||
const close = iterator.return?.bind(iterator)
|
||||
if (close) await close()
|
||||
|
||||
@@ -72,10 +72,10 @@ describe('BlockAssembler', () => {
|
||||
it('mustGet throws when an index is missing from the partials map (invariant violation)', () => {
|
||||
const assembler = new BlockAssembler()
|
||||
// Force the invariant violation: manually corrupt the data structures.
|
||||
/* eslint-disable */
|
||||
/* oxlint-disable */
|
||||
const hack = assembler as any
|
||||
hack.order.push(99)
|
||||
/* eslint-enable */
|
||||
/* oxlint-enable */
|
||||
expect(() => assembler.blocks()).toThrow('BlockAssembler invariant violated')
|
||||
})
|
||||
|
||||
|
||||
@@ -756,7 +756,7 @@ describe('LlmService', () => {
|
||||
return {
|
||||
[Symbol.asyncIterator](): AsyncIterator<StreamChunk> {
|
||||
// Third-party adapters can reject with arbitrary values.
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
|
||||
// oxlint-disable-next-line typescript/prefer-promise-reject-errors
|
||||
return { next: () => Promise.reject('plain provider failure') }
|
||||
},
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ export class TokenMeterService extends Service {
|
||||
}
|
||||
|
||||
while (state.consumedEvents < session.events.length) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- contiguous session seqs index the durable log
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion -- contiguous session seqs index the durable log
|
||||
const event = session.events[state.consumedEvents]!
|
||||
this._foldEvent(session, state, event)
|
||||
state.consumedEvents += 1
|
||||
@@ -226,7 +226,7 @@ export class TokenMeterService extends Service {
|
||||
}
|
||||
|
||||
// assistant/message is surface-mandatory at every append/seed boundary.
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
const eventTokens = surface!.tokens
|
||||
if (event.data.usage !== undefined && nextHeader !== undefined) {
|
||||
const providerAssistantTokens = this._estimateProviderAssistant(
|
||||
@@ -334,7 +334,7 @@ export class TokenMeterService extends Service {
|
||||
// Session construction validates contiguous seqs, and the explicit
|
||||
// earlier-than-assistant check above therefore guarantees existence.
|
||||
const source = session.events[seq]
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
const sourceEvent = source!
|
||||
if (sourceEvent.type !== 'assistant/chunk') {
|
||||
throw new Error(`token meter: assistant/message at seq ${event.seq} source seq ${seq} is not assistant/chunk`)
|
||||
|
||||
@@ -39,7 +39,7 @@ export class SessionQueryError extends HarnessError {
|
||||
declare readonly code: SessionQueryErrorCode
|
||||
|
||||
// The base stores the value; this signature narrows its open string code.
|
||||
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
|
||||
// oxlint-disable-next-line typescript/no-useless-constructor
|
||||
constructor(message: string, code: SessionQueryErrorCode, options?: ErrorOptions) {
|
||||
super(message, code, options)
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ export function traceEvent(
|
||||
}
|
||||
|
||||
// The target check above proves the parallel record exists at this index.
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
const targetRecord = analysis.records[seq]!
|
||||
const replacedBy = analysis.replacedBy.get(seq)
|
||||
return {
|
||||
@@ -225,7 +225,7 @@ function buildDescendants(
|
||||
const stack = [{ sessionId, descendants }]
|
||||
while (stack.length > 0) {
|
||||
// The length guard proves a frame exists.
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
const frame = stack.pop()!
|
||||
const nodes: SessionLineageNode[] = []
|
||||
for (const child of childrenByParent.get(frame.sessionId) ?? []) {
|
||||
@@ -235,7 +235,7 @@ function buildDescendants(
|
||||
}
|
||||
for (let index = nodes.length - 1; index >= 0; index -= 1) {
|
||||
// The loop bounds prove this indexed node exists.
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
const node = nodes[index]!
|
||||
stack.push({ sessionId: node.session.header.id, descendants: node.descendants })
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ function expectCode(code: SessionQueryErrorCode): Error {
|
||||
function rejectUnknown<T>(reason: unknown): Promise<T> {
|
||||
return new Promise<T>((_resolve, reject) => {
|
||||
// Exercise containment for an implementation that violates the Error rejection convention.
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
|
||||
// oxlint-disable-next-line typescript/prefer-promise-reject-errors
|
||||
reject(reason)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1444,7 +1444,7 @@ describe('search paging, prior-history bounds, titles, and cancellation', () =>
|
||||
},
|
||||
])('fails generic when inspecting $name is unsafe', async ({ secrets, diagnostic, failure }) => {
|
||||
const mounted = await mount()
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- hostile unknown rejection is the scenario
|
||||
// oxlint-disable-next-line typescript/prefer-promise-reject-errors -- hostile unknown rejection is the scenario
|
||||
FakeQuery.sessionSearch = () => Promise.reject(failure())
|
||||
const warn = vi.spyOn(mounted.ctx.logger, 'warn').mockImplementation(() => undefined)
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ class CooperativeAdapter extends LlmAdapter {
|
||||
if (signal === undefined) throw new Error('expected title request signal')
|
||||
await new Promise<never>((_resolve, reject) => {
|
||||
const rejectAbort = (): void => {
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- exercise exact AbortSignal.reason propagation
|
||||
// oxlint-disable-next-line typescript/prefer-promise-reject-errors -- exercise exact AbortSignal.reason propagation
|
||||
reject(signal.reason)
|
||||
}
|
||||
if (signal.aborted) {
|
||||
|
||||
@@ -381,7 +381,7 @@ class SkillWatchManager {
|
||||
const current = await resolveRootWatchMode(state.root.path)
|
||||
// A child unlink can publish an empty catalog before root unlinkDir arrives.
|
||||
// Discovery therefore revalidates the retained handle independently.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- watcher callbacks can mark unhealthy while the probe awaits
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-condition -- watcher callbacks can mark unhealthy while the probe awaits
|
||||
if (!state.unhealthy && sameWatchMode(watcher.mode, current)) return
|
||||
}
|
||||
await this.replaceWatcher(state)
|
||||
@@ -398,7 +398,7 @@ class SkillWatchManager {
|
||||
/* v8 ignore next -- The loop returns no handle only when teardown wins between awaited probes. */
|
||||
if (watcher === undefined) return
|
||||
/* v8 ignore start -- Post-open teardown is timing-dependent; the disposal race has an explicit integration test. */
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- teardown can race awaited watcher startup
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-condition -- teardown can race awaited watcher startup
|
||||
if (this.closing || state.owners.size === 0) {
|
||||
await this.closeWatcher(watcher)
|
||||
return
|
||||
@@ -407,7 +407,7 @@ class SkillWatchManager {
|
||||
state.watcher = watcher
|
||||
state.unhealthy = false
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- teardown can race awaited watcher startup
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-condition -- teardown can race awaited watcher startup
|
||||
if (!this.closing) {
|
||||
state.unhealthy = true
|
||||
this.ctx.logger.warn(`skill-local: failed to watch ${state.root.path}: ${errorMessage(error)}`)
|
||||
|
||||
@@ -267,7 +267,7 @@ export class SkillService extends Service {
|
||||
invalidateCache()
|
||||
}
|
||||
}, 'skills.registerProvider()')
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- synchronous cleanup; preserve exact disposer identity
|
||||
// oxlint-disable-next-line typescript/no-misused-promises -- synchronous cleanup; preserve exact disposer identity
|
||||
return dispose
|
||||
} catch (error) {
|
||||
lifecycle.abort(error)
|
||||
@@ -307,7 +307,7 @@ export class SkillService extends Service {
|
||||
invalidateCache()
|
||||
}
|
||||
}, 'skills.register()')
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity
|
||||
// oxlint-disable-next-line typescript/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity
|
||||
return dispose
|
||||
}
|
||||
|
||||
|
||||
@@ -761,7 +761,7 @@ describe('SkillService registry', () => {
|
||||
const warnings: string[] = []
|
||||
ctx.logger.warn = ((message: unknown) => { warnings.push(String(message)) }) as typeof ctx.logger.warn
|
||||
const disposeThrowing = ctx.on('skills/change', () => { throw new Error('observer threw') })
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- deliberate rejection proves notification containment
|
||||
// oxlint-disable-next-line typescript/no-misused-promises -- deliberate rejection proves notification containment
|
||||
const disposeRejecting = ctx.on('skills/change', () => Promise.reject(new Error('observer rejected')))
|
||||
let observed = 0
|
||||
const disposeObserver = ctx.on('skills/change', () => { observed += 1 })
|
||||
@@ -907,7 +907,7 @@ describe('SkillService registry', () => {
|
||||
name: 'hostile-failure',
|
||||
list() {
|
||||
// Deliberately violate the provider contract to prove containment is total.
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
|
||||
// oxlint-disable-next-line typescript/prefer-promise-reject-errors
|
||||
return Promise.reject(hostileFailure)
|
||||
},
|
||||
async get() {
|
||||
|
||||
@@ -268,7 +268,7 @@ function catalogHistory(agent: Agent): { visibleDigest?: string; published: bool
|
||||
let published = false
|
||||
for (let index = events.length - 1; index >= 0; index -= 1) {
|
||||
// The loop bounds prove the read-only event view contains this index.
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
const event = events[index]!
|
||||
if (event.type !== 'user/message'
|
||||
|| event.data.source.kind !== 'plugin'
|
||||
|
||||
@@ -56,7 +56,7 @@ class JsonKvUnit implements KvUnit {
|
||||
private readonly onClose: () => void,
|
||||
) {}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/require-await -- async keeps the closed guard a rejection, not a synchronous throw
|
||||
// oxlint-disable-next-line typescript/require-await -- async keeps the closed guard a rejection, not a synchronous throw
|
||||
async loadAll(): Promise<{ tables: Record<string, Record<string, unknown>>; global: unknown }> {
|
||||
this.assertOpen()
|
||||
const tables: Record<string, Record<string, unknown>> = {}
|
||||
|
||||
@@ -145,7 +145,7 @@ export async function startInProcessRun(
|
||||
// Close the narrow handoff race before installing the live-run listener.
|
||||
// Static analysis does not model the abort that may land between the
|
||||
// factory's listener detachment and this continuation.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-condition
|
||||
if (request.signal.aborted) {
|
||||
flags.cancelled = true
|
||||
await handle.dispose()
|
||||
|
||||
@@ -194,7 +194,7 @@ export class SubagentService extends Service {
|
||||
*/
|
||||
registerProvider(provider: SubagentProvider): () => void {
|
||||
const name = provider.name
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity
|
||||
// oxlint-disable-next-line typescript/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity
|
||||
return this.ctx.effect(function* (this: SubagentService) {
|
||||
if (this.providers.has(name)) {
|
||||
throw new SubagentError(`a subagent provider named "${name}" is already registered`, 'DUPLICATE_PROVIDER')
|
||||
|
||||
@@ -226,7 +226,7 @@ describe('SubagentService', () => {
|
||||
const heard: string[] = []
|
||||
ctx.on('subagent/provider-removed', () => { throw new Error('sync boom') })
|
||||
// Runtime listeners may return thenables even though the declaration's observable result is void.
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- exercises rejected-listener containment
|
||||
// oxlint-disable-next-line typescript/no-misused-promises -- exercises rejected-listener containment
|
||||
ctx.on('subagent/provider-removed', async () => { throw new Error('async boom') })
|
||||
ctx.on('subagent/provider-removed', () => { throw { toString: () => { throw new Error('coercion') } } })
|
||||
ctx.on('subagent/provider-removed', name => void heard.push(name))
|
||||
|
||||
@@ -192,7 +192,7 @@ export class InvariantService extends Service {
|
||||
}
|
||||
// Cordis attaches setup thenability and async teardown to this callable;
|
||||
// the service seam intentionally exposes only the conventional disposer.
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- the extra runtime shape stays private.
|
||||
// oxlint-disable-next-line typescript/no-misused-promises -- the extra runtime shape stays private.
|
||||
return registration
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ export class TypertRegistry extends Service {
|
||||
for (const record of schemaRecords) schemas.delete(record.key)
|
||||
}
|
||||
}, 'typert.register()')
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- synchronous cleanup; preserve Cordis disposer identity
|
||||
// oxlint-disable-next-line typescript/no-misused-promises -- synchronous cleanup; preserve Cordis disposer identity
|
||||
return dispose
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ describe('CommandService', () => {
|
||||
|
||||
const warn = vi.spyOn(ctx.logger, 'warn').mockImplementation(() => undefined)
|
||||
ctx.on('commands/change', () => { throw new Error('observer threw') })
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- exercises rejected-listener containment
|
||||
// oxlint-disable-next-line typescript/no-misused-promises -- exercises rejected-listener containment
|
||||
ctx.on('commands/change', () => Promise.reject(new Error('observer rejected')))
|
||||
const afterFailures = vi.fn()
|
||||
ctx.on('commands/change', afterFailures)
|
||||
@@ -229,7 +229,7 @@ describe('CommandService', () => {
|
||||
ctx.commands.register({
|
||||
name: 'reject-value',
|
||||
description: 'Reject a non-Error value',
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- exercise untyped plugin normalization
|
||||
// oxlint-disable-next-line typescript/prefer-promise-reject-errors -- exercise untyped plugin normalization
|
||||
handler: () => Promise.reject('not an Error'),
|
||||
})
|
||||
await expect(ctx.commands.execute(agent, '/reject-value', new AbortController().signal))
|
||||
@@ -239,7 +239,7 @@ describe('CommandService', () => {
|
||||
ctx.commands.register({
|
||||
name: 'reject-hostile',
|
||||
description: 'Reject an unrenderable value',
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- exercise hostile plugin normalization
|
||||
// oxlint-disable-next-line typescript/prefer-promise-reject-errors -- exercise hostile plugin normalization
|
||||
handler: () => Promise.reject(hostile),
|
||||
})
|
||||
await expect(ctx.commands.execute(agent, '/reject-hostile', new AbortController().signal))
|
||||
|
||||
@@ -366,7 +366,7 @@ export function createTuiChat(
|
||||
// the controller needs `appendNotice`/`overlayManager`, defined after that
|
||||
// closure. Declare here, assign once after those exist, and defer the first
|
||||
// `updatePromptValues()` call until after the assignment so no read precedes it.
|
||||
// eslint-disable-next-line prefer-const -- single assignment is a forward-reference, not a const.
|
||||
// oxlint-disable-next-line prefer-const -- single assignment is a forward-reference, not a const.
|
||||
let modelController!: ModelController
|
||||
const now = (): number => runtime.now?.() ?? Date.now()
|
||||
const agentStatus = (): AgentStatus => agent.status
|
||||
|
||||
@@ -548,7 +548,7 @@ describe('dsh-workflow-workerthread', () => {
|
||||
// The rejection VALUE's own coercion throws: a warn built with bare
|
||||
// String(error) would itself throw, skipping the ChildDisposed ack
|
||||
// and wedging the script's finally until the grace/terminate path.
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- the non-Error rejection IS the scenario under test
|
||||
// oxlint-disable-next-line typescript/prefer-promise-reject-errors -- the non-Error rejection IS the scenario under test
|
||||
dispose: () => Promise.reject({ toString: () => { throw new Error('coercion trap') } }),
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ describe('dsh-workflow (interface)', () => {
|
||||
const warn = vi.spyOn(ctx.logger, 'warn').mockImplementation(() => ctx.logger)
|
||||
const seen: string[] = []
|
||||
// Runtime listeners may return thenables even though the declaration's observable result is void.
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- exercises rejected-listener containment
|
||||
// oxlint-disable-next-line typescript/no-misused-promises -- exercises rejected-listener containment
|
||||
ctx.on('workflow/agent-start', async () => { throw new Error('async observer failed') })
|
||||
ctx.on('workflow/agent-start', (_info, agent) => { seen.push(agent.label) })
|
||||
const engine = ctx.workflows as StubEngine
|
||||
|
||||
Reference in New Issue
Block a user