import { isRegisteredSubagentChild, isSubagentExecutionContext, type SubagentDetectionContext, } from "#src/authority/subagent-context"; import type { SubagentSessionRegistry } from "#src/authority/subagent-registry"; import type { PathFlavor } from "#src/path/path-flavor"; /** * Narrow seam for the ask-path consumers: "is the current session a subagent?" * * `selectAuthorizer`/`AuthorizerSelection` and `ForwardingManager` depend on * this single-method view so their unit tests inject a one-field fake without * casts. It is the Authorizer-selection predicate the Phase 9 spine consumes. */ export interface SubagentDetector { isSubagent(ctx: SubagentDetectionContext): boolean; } /** * Narrow seam for the service-publication guard (#302): "is the current * session a registered in-process child?" * * `PermissionServiceLifecycle` depends on this single-method view so a * registered child never publishes over its parent's process-global slot. */ export interface RegisteredChildDetector { isRegisteredChild(ctx: SubagentDetectionContext): boolean; } /** Composition-root inputs for {@link SubagentDetection}. */ export interface SubagentDetectionDeps { subagentSessionsDir: string; flavor: PathFlavor; registry?: SubagentSessionRegistry; } /** * Single owner of subagent detection. * * Constructed once in the composition root with the detection inputs * (`subagentSessionsDir`, `flavor`, `registry`) and shared across every * consumer, replacing the dep triple those consumers previously threaded * individually. Delegates to the pure detection functions in * {@link ./subagent-context}, holding only the deps. */ export class SubagentDetection implements SubagentDetector, RegisteredChildDetector { constructor(private readonly deps: SubagentDetectionDeps) {} isSubagent(ctx: SubagentDetectionContext): boolean { return isSubagentExecutionContext( ctx, this.deps.subagentSessionsDir, this.deps.flavor, this.deps.registry, ); } isRegisteredChild(ctx: SubagentDetectionContext): boolean { return this.deps.registry ? isRegisteredSubagentChild(ctx, this.deps.registry) : false; } }