import { type CapabilitySource } from "./capability-catalog.js"; import { type NativeTaskTools } from "./native-task-policy.js"; import type { FeatureFlagCache } from "./feature-flag-cache.js"; import { type FeatureOwner } from "./feature-flags.js"; import { CopilotClient, type Tool } from "@github/copilot-sdk"; import { ManagedSession } from "./managed-session.js"; import type { SessionStateStore } from "./session-store.js"; import { type AbortTurnResult, type ManagedSessionConfig, type SerializableSessionConfig } from "./types.js"; import type { ModelProviderRegistry } from "./model-providers.js"; import type { SessionCatalog } from "./cms.js"; import type { FactStore } from "./facts-store.js"; import type { GraphStore } from "./graph-store.js"; export declare const SESSION_LOCK_ACQUIRE_TIMEOUT_CODE = "PILOTSWARM_SESSION_LOCK_ACQUIRE_TIMEOUT"; export declare class SessionLockAcquireTimeoutError extends Error { readonly code = "PILOTSWARM_SESSION_LOCK_ACQUIRE_TIMEOUT"; readonly sessionId: string; readonly operation: string; readonly waitedMs: number; constructor(sessionId: string, operation: string, waitedMs: number); } export declare function isSessionLockAcquireTimeoutError(error: unknown): error is SessionLockAcquireTimeoutError; type SessionTraceWriter = (message: string) => void; /** * One loadable copy of a named agent. * * Agent-package scope shadowing means one agent NAME can be served by several * enabled packages at once (a shared copy plus per-user copies). Each copy is * a distinct prompt/descriptor; which one a session gets is decided per * session owner (`pickAgentCopyForOwner`), the same "own copy shadows shared" * rule the registry resolver applies. Non-package (deployment plugin) agents * carry no package fields. */ export interface AgentCopyEntry { prompt: string; /** V2 declared-skill composition excludes unrelated published packages. */ baseV2Prompt?: string; /** Current named-agent declarations; [] explicitly means no additional tools. */ toolNames?: string[]; nativeTaskTools?: NativeTaskTools; kind: "app-agent" | "app-system-agent" | "pilotswarm-system-agent"; descriptor?: import("./prompt-layers.js").PromptLayerDescriptor; packageId?: string; packageScope?: "shared" | "user"; packageOwner?: { provider: string; subject: string; } | null; } /** * The lookup value for one agent name: a deterministic default copy * (deployment code beats shared package beats user package), plus every copy * when the name is served by more than one. */ export interface AgentPromptEntry extends AgentCopyEntry { copies?: AgentCopyEntry[]; } export declare class PackageToolBindingError extends Error { readonly toolName: string; readonly code = "PACKAGE_TOOL_REQUIRES_BOUND_AGENT"; constructor(toolName: string); } export declare class BoundAgentPackageUnavailableError extends Error { readonly packageId: string; readonly code = "BOUND_AGENT_PACKAGE_UNAVAILABLE"; constructor(packageId: string, message?: string); } /** Key under which a package copy's per-agent config (MCP) is registered. */ export declare function packageAgentKey(packageId: string, agentName: string): string; /** Owner key used to match a session owner against a package copy's owner. */ export declare function agentOwnerKey(owner?: { provider?: string | null; subject?: string | null; } | null): string | null; /** * Which copy of an agent name does THIS session get? * * Runs per turn, so enabling/disabling a copy re-resolves exactly like a * republish does — live sessions follow the registry's current answer, they * are not pinned to a copy. * * FAIL CLOSED, matching resolveAgentDefinitionForCaller: a user-scope copy is * PRIVATE to its owner, and the worker holds every tenant's copies at once. * The order is (1) the session owner's OWN user copy, (2) the best copy that * is public by construction — a deployment agent or a shared package. A * user-scope copy owned by someone ELSE is NEVER served, even when it is the * only copy of the name left: returning it would leak that owner's prompt, * MCP grants, and tool handlers into this session (they all follow the copy * picked here). undefined means "no package overlay for this session" — the * same outcome as the agent having been deleted, which is correct. */ export declare function pickAgentCopyForOwner(entry: AgentPromptEntry | undefined, ownerKey: string | null): AgentCopyEntry | undefined; /** Resolve an already-authorized exact package copy while rechecking owner visibility. */ export declare function pickAgentCopyByPackageIdForOwner(entry: AgentPromptEntry | undefined, packageId: string, ownerKey: string | null): AgentCopyEntry | undefined; /** Worker-level defaults — applied to every session. */ export interface WorkerDefaults { getCapabilitySources?: () => CapabilitySource[]; /** Host-reserved fact key prefixes, see PilotSwarmWorkerOptions.reservedFactPrefixes. */ reservedFactPrefixes?: string[]; nativeSubagents?: "off" | "sync"; frameworkBasePrompt?: string; frameworkBaseToolNames?: string[]; appDefaultPrompt?: string; appDefaultToolNames?: string[]; /** Backward-compatible alias for older code paths/tests. */ systemMessage?: string; /** Raw prompt lookup for named and system agents bound directly to sessions. */ agentPromptLookup?: Record; /** Descriptor for the PilotSwarm framework base layer (from system default.agent.md). */ frameworkBaseDescriptor?: import("./prompt-layers.js").PromptLayerDescriptor; /** Descriptor for the app default layer (from app default.agent.md or inline config). */ appDefaultDescriptor?: import("./prompt-layers.js").PromptLayerDescriptor; /** Skill directories to pass to the Copilot SDK. */ skillDirectories?: string[]; /** V2 only: SDK-visible skill dirs after filtering by the session owner's verified package provenance. */ getBaseV2SkillDirectories?: (owner: FeatureOwner | null) => string[]; /** Custom agents to pass to the Copilot SDK. */ customAgents?: Array<{ name: string; description?: string; prompt: string; tools?: string[] | null; skills?: string[]; mcpServers?: Record; }>; /** * Every registered skill (deployment + packages), held BY REFERENCE from * the worker. Progressive discovery: the base prompt carries a one-line * index of names and descriptions, and the `load_skill` tool returns a * body on demand — nothing is inlined unless an agent declares it. */ skills?: Array<{ name: string; description: string; prompt: string; dir?: string; }>; /** * Private skills from USER-scope agent packages, keyed by owner * (`agentOwnerKey`). A session may load the ones its own owner * published; they are never offered to anybody else. Held by reference, * refilled in place on plugin reload. */ ownerScopedSkills?: Map>; /** * Deployment MCP catalog (merged `.mcp.json` map). NOT applied to * sessions wholesale — a session receives exactly its bound agent's * resolved map from `agentMcpServers` (capability-profiles Phase 1). */ mcpServers?: Record; /** Resolved per-agent MCP server maps, keyed by bound agent name. */ agentMcpServers?: Record>; /** * Resolved base MCP map applied to EVERY session: base (default) agent * opt-ins plus direct worker-config servers (legacy semantics). */ baseMcpServers?: Record; /** * Catalog servers restricted with `allowedAgents` (server name → allowed * agent identities). Held BY REFERENCE from the worker, which clears and * refills it in place on every plugin reload. */ mcpAllowedAgents?: Map>; /** Every server name the deployment defines — a package may not redefine one. Held BY REFERENCE. */ deploymentMcpNames?: Set; /** * @deprecated Use `modelProviders` instead. Kept for backwards compatibility. * Custom LLM provider config (BYOK). Passed to every session. */ provider?: { type?: "openai" | "azure" | "anthropic"; baseUrl: string; apiKey?: string; azure?: { apiVersion?: string; }; }; /** Multi-provider model registry. Takes precedence over `provider`. */ modelProviders?: ModelProviderRegistry; /** Wall-clock turn cap in ms. 0 = no cap; undefined = 20-minute default. */ turnTimeoutMs?: number; /** Turn inactivity watchdog in ms. 0 = disabled; undefined = 5-minute default. */ turnInactivityTimeoutMs?: number; } /** * SessionManager — singleton per worker node. * Owns session lifecycle, wraps CopilotClient. * * Three ways a session appears: * 1. Brand new → createSession * 2. Same node, still warm → getSession returns it * 3. Post-hydration → local files exist → resumeSession * * @internal */ /** * Capability declaration for a model the Copilot catalog does not know. * * Returns undefined when the catalog says nothing useful — an empty override * is worse than none, since it would assert "no vision, no reasoning" rather * than "unknown". * * @internal Exported for test/unit/byok-context-window.test.mjs only. */ export declare function buildByokModelCapabilities(descriptor: any, contextTier?: string): { supports?: Record; limits?: Record; } | undefined; export declare class SessionManager { private githubToken?; /** * Resolved inspect viewers, keyed by session id. Static so it is shared * across manager instances in a worker process. * * The TTL alone does NOT bound this map: it is only consulted on read, so * a session touched once and never again leaves its entry behind forever. * A long-lived worker sees an unbounded number of session ids, so entries * are swept on insert once the map crosses a threshold. */ private static _inspectViewerCache; private static readonly INSPECT_VIEWER_CACHE_SWEEP_AT; private clients; /** * Backward-compat accessor for the default-token CopilotClient. * * The internal pool is keyed by transport and GitHub Copilot token (so * per-user keys can override `GITHUB_TOKEN` for a specific session). * Tests that predate the pool — and a couple of internal call sites * that assume a single shared client — still read or assign * `manager.client = fakeClient` to inject a stub. Honor that by * populating both the empty-key slot AND the worker-default token * slot so `ensureClient()` returns the fake whether or not the * default `GITHUB_TOKEN` was set on the constructor. */ get client(): CopilotClient | undefined; set client(value: CopilotClient | undefined); private sessions; private featureFlags; private unsubscribeFeatureFlags; /** Live in-memory session count — worker-registry health reporting. */ get activeSessionCount(): number; /** * Records which CopilotClient each warm session is bound to (keyed by * the GitHub Copilot token plus native/BYOK transport namespace). When * the token or transport changes (for example the owner edited their key in the * Admin Console), the warm session is destroyed at the start of the * next `getOrCreate` call so the next resume binds to the right * client. Sessions never appear in this map until they are actually * created/resumed in `_getOrCreateUnlocked`. */ private sessionClientKeys; private sessionStore; /** In-memory configs with non-serializable fields (tools, hooks). */ private sessionConfigs; /** Only application-supplied tools; resolved registry/platform handlers are never cached as inputs. */ private sessionApplicationTools; /** One authorized agent snapshot per turn, also used by dynamic prompt callbacks. */ private sessionAgentCopies; /** CLI declarations and MCP grants require a new SDK handle when they change. */ private sessionBindingFingerprints; /** Worker-level tool registry — shared reference from PilotSwarmWorker. */ private toolRegistry; /** Per-package tool maps, so a session prefers ITS package's handler on a name collision. */ private packageToolRegistry; /** Package-owned names cannot be attached without the matching agent package binding. */ private packageToolNames; /** Names registered by deployment code — a package tool must never shadow these. */ private staticToolNames; /** Worker-level defaults for building blocks. */ private workerDefaults; /** Base directory for local session state files. */ private sessionStateDir; /** Shared facts store used to build always-on facts tools. */ private factStore; /** Optional, separately-injected graph store (07 D2). Present iff a * graphDatabaseUrl was configured; gates graph-tool registration. */ private graphStore; /** Shared CMS catalog used to build always-on inspect tools. */ private sessionCatalog; /** * Last-seen fingerprint of each dynamic system-message section, per * session. The provider caches the request prefix, so any byte that * moves in the system message between two turns costs the whole cache * behind it. Measured on waldemort chk (2026-08-30): the wake-up note * (fixed by orchestration 1.0.71) was one mover, but user→user turns * still changed the prompt size 29% of the time with no note present. * This map is how we find the rest: a `session.prompt_sections` event is * recorded whenever a section's hash changes, naming the section and * the size delta. Read it next to the CLI's "(N chars)" echo — a size * change with no section event means the mover is on the CLI side. */ private promptSectionDigests; /** Duroxide client used by tuner-only inspect tools. */ private _duroxideClient; private _refreshModelProviders; /** Lineage lookup for ancestor/descendant facts access. */ private _getLineageSessionIds; /** Per-session critical sections; protects the SDK session handle and local session.db. */ private sessionLocks; /** Last local activity per session — feeds the autonomous eviction clock. */ private sessionLastTouchedAt; private readonly adminScope; constructor(githubToken?: string | undefined, sessionStore?: SessionStateStore | null, workerDefaults?: WorkerDefaults, sessionStateDir?: string); /** * Artifact store, assigned by the worker after construction. * * Set here rather than taken as a constructor argument because the worker * builds its store after the SessionManager, and the only consumer is the * write bundle's patch artifacts — which degrade to a clear refusal when * it is absent rather than failing a turn. */ artifactStore: import("./session-store.js").ArtifactStore | null; /** Store full config (with tools/hooks) for a session. Called by PilotSwarmClient. */ setConfig(sessionId: string, config: ManagedSessionConfig): void; private _allowedModelProviderIds; /** Get a viewer-scoped model summary for in-session LLM tools. */ getModelSummary(sessionId: string): Promise; normalizeModelRefForSession(sessionId: string, model: string, options?: { requireQualified?: boolean; }): Promise; /** * Normalize a model reference against the configured registry. * Throws for unknown models. When `requireQualified` is true, the caller * must provide the exact `provider:model` string rather than a bare alias. */ normalizeModelRef(model?: string, options?: { requireQualified?: boolean; }): string | undefined; resolveModelSwitchConfig(model: string, reasoningEffort?: import("./model-providers.js").ReasoningEffort | null): { model: string; reasoningEffort: import("./model-providers.js").ReasoningEffort | null; }; resolveModelSwitchConfigForSession(sessionId: string, model: string, reasoningEffort?: import("./model-providers.js").ReasoningEffort | null): Promise<{ model: string; reasoningEffort: import("./model-providers.js").ReasoningEffort | null; }>; /** * Cached Copilot model catalogs for vision-capability lookups (5 min TTL), * keyed by client token key — capability entitlements are PER TOKEN * (per-user keys can differ from the deployment default), so one shared * cache would leak one identity's catalog onto another's sessions. */ private modelCatalogCaches; /** * Resolve whether a session's model can be shown images, plus the * provider's vision limits. `modelRef` is the session-config value * (qualified `provider:model`, bare, or undefined → worker default). * * When `opts.sessionId` is given, the catalog is consulted on the SAME * CopilotClient that serves that session's turns (per-user/system key * aware) — the only token whose entitlements matter, because it is the * one the image blobs ride out on. Without a sessionId (tests, generic * callers) the default-token client is used as before. * * `known: false` means the catalog had no entry (BYOK model, catalog * fetch failure, no usable client, …) — callers must treat that as "no * vision" and degrade gracefully rather than guessing. */ getModelVisionInfo(modelRef?: string, opts?: { sessionId?: string; }): Promise<{ modelId: string; known: boolean; vision: boolean; supportedMediaTypes?: string[]; maxImages?: number; maxImageBytes?: number; }>; /** * Set the worker-level tool registry. Called by PilotSwarmWorker. * * `opts.byPackage` carries each agent package's own tool map so a session * bound to a package copy resolves colliding tool names to ITS copy's * handler. `opts.staticNames` marks deployment-registered tools, which win * every collision (a package must not shadow deployment code). */ setToolRegistry(registry: Map>, opts?: { byPackage?: Map>>; staticNames?: Set; }): void; /** Set the cluster facts store for always-on facts tools. */ setFactStore(factStore: FactStore | null): void; /** Set the optional graph store (07 D2). `null`/absent ⇒ no graph tools. */ setGraphStore(graphStore: GraphStore | null): void; /** Set the CMS catalog for always-on inspect tools (e.g. read_agent_events). */ setSessionCatalog(catalog: SessionCatalog | null): void; setFeatureFlagCache(cache: FeatureFlagCache | null): void; /** * Hot-swap the model-provider registry after a config-file change on * disk (ConfigMap update). Applies to all subsequent model resolution; * live warm sessions keep their bound client until their next * getOrCreate re-resolves. */ setModelProviders(registry: import("./model-providers.js").ModelProviderRegistry | null): void; setModelProvidersRefresher(refresh: (() => Promise) | null): void; refreshModelProviders(): Promise; /** Set the duroxide client for tuner-only inspect tools. */ setDuroxideClient(client: any): void; /** Set the lineage lookup for ancestor/descendant facts access. */ setLineageSessionLookup(fn: ((sessionId: string) => Promise) | null): void; /** @deprecated Use setLineageSessionLookup. */ setDescendantSessionLookup(fn: ((sessionId: string) => Promise) | null): void; /** * Resolve the default model's SDK provider config. * Used by activities (e.g. summarizeSession) that need a lightweight LLM * without requiring a GitHub token. */ resolveDefaultProvider(): { modelName: string; sdkProvider: any; } | undefined; /** * Resolve an arbitrary model ref (or the deployment default) to ephemeral * SDK session options. Null when the ref doesn't resolve — the regen * distiller walks its fallback chain on that (a dead session model must * not block the regeneration that exists to escape it). */ resolveModelSessionOptions(ref?: string): { model?: string; provider?: unknown; gitHubToken?: string; } | null; /** Ensure the CopilotClient is started. */ private ensureClient; /** * Return the GitHub Copilot token that should back the CopilotClient * used to resume/create the given session id. Resolution order: * * 1. Per-user override on the session's owner row in CMS * (`users.github_copilot_key`). Only applied when the session's * effective model resolves to a `type=github` provider — for * BYOK Anthropic/OpenAI sessions the SDK never reads the token * so there is no point spinning up a per-user CLI process. * 2. Worker-default resolution (constructor token > registry). * * Returns `undefined` to mean "use the worker default", which is the * shape `ensureClient` already understands. */ private _resolveSessionGitHubToken; /** * Resolve a pool key without ever passing its transport namespace as an * authentication token. Shared by catalog lookups and session teardown. */ private ensureClientForKey; private _ensureClientForSession; private _missingSessionStateError; private _resetSessionState; /** * Epoch-start reset (session regeneration): discard the warm handle, the * SDK's registration of the id, and the local dir — and clear ONLY the * current epoch's (empty or partial) store chain. Prior epochs' snapshots * and the legacy chain are never touched; they are the archive/rollback * record. */ private _resetSessionStateForEpoch; private _withSessionLock; withRunTurnLock(sessionId: string, operation: string, fn: () => Promise, options?: { trace?: SessionTraceWriter; }): Promise; /** * Autonomous eviction sweep (lifecycle protocol §3.4): local session * state is a cache. A session idle past `evictAfterMs` is reclaimed * without telling anyone — sessions with a committed snapshot marker * are simply destroyed + deleted (the store already holds their state; * the next runTurn self-validates and hydrates); unmarked (legacy) * sessions are dehydrated the old way so their only copy is preserved. * Returns the number of sessions reclaimed. */ sweepIdleSessions(evictAfterMs: number): Promise; /** * Stop-turn interrupt primitive: abort the warm session's in-flight turn. * * LOCK-BYPASSING BY DESIGN — never take _withSessionLock here. runTurn * holds the session lock for the entire turn, so a lock-taking stop would * run only after the turn ended (defeating mid-flight stop). This method * only reads the warm map and touches ManagedSession in-memory state; the * runTurn activity remains the single writer of turn results. * * Sequence: set the stop marker (so the unwind classifies as "stopped"), * send the SDK abort, wait bounded time for the turn to unwind, and if the * SDK never fires session.idle escalate with forceSettleTurn() + warm * session invalidation (stop-turn plan, edge E3). */ abortWarmSessionTurn(sessionId: string, opts: { reason: string; expectedTurnIndex?: number; unwindGraceMs?: number; }): Promise; /** * Get existing session or create/resume one. * Merges: worker defaults → serializable config (from client) → in-memory config (tools/hooks). */ getOrCreate(sessionId: string, serializableConfig: SerializableSessionConfig, options?: { turnIndex?: number; trace?: SessionTraceWriter; lockHeld?: boolean; transcriptEpoch?: number; epochStart?: boolean; }): Promise; private _getOrCreateUnlocked; /** Get a session by ID (null if not in memory on this node). */ get(sessionId: string): ManagedSession | null; /** Root directory holding per-session state dirs. */ getSessionStateDir(): string; /** Release snapshots with their SDK handle; application tools survive ordinary hydration. */ private _forgetWarmSession; /** * Destroy the in-memory ManagedSession only — disk state untouched. * Used by the lifecycle preamble before overwriting local files with a * hydrated snapshot (a warm session bound to the old files must not * survive the swap). Caller holds the per-session run-turn lock. */ dropWarmSession(sessionId: string): Promise; /** * Dehydrate a session: snapshot to the session store, release in-memory state. * * Order of operations matters here. The Copilot SDK's `disconnect()` is * documented to preserve the on-disk session directory intact (verified * empirically against @github/copilot 1.0.36). We: * 1. Take a pre-destroy checkpoint of the live directory as a safety net. * 2. Disconnect the in-memory session, retrying with `resumeSession` if * the connection was already torn down (e.g. CLI process died). * 3. Persist the post-disconnect snapshot to the session store. This * is a single-shot attempt because the SDK does not asynchronously * flush after disconnect: the files either exist or they don't. * 4. If the post-disconnect snapshot is missing (which would indicate * a future SDK regression), fall back to the pre-destroy checkpoint. */ dehydrate(sessionId: string, reason: string, options?: { trace?: SessionTraceWriter; lockHeld?: boolean; }): Promise; private _dehydrateUnlocked; /** * Hydrate session state from the configured session store to local disk. * The next getOrCreate() will detect local files and resume. */ hydrate(sessionId: string, options?: { trace?: SessionTraceWriter; lockHeld?: boolean; }): Promise; private _hydrateUnlocked; /** * Return true when the next turn must hydrate state from the session store. * This supports abrupt worker loss and direct worker-side dehydration. */ needsHydration(sessionId: string, options?: { trace?: SessionTraceWriter; }): Promise; /** * Destroy a session and remove from tracking. */ destroySession(sessionId: string, options?: { lockHeld?: boolean; }): Promise; /** * Drop the warm in-memory session handle without deleting any persisted * local/session-store state. Used when the underlying Copilot session * becomes invalid and we want the next getOrCreate() to resume/hydrate it. */ invalidateWarmSession(sessionId: string, options?: { lockHeld?: boolean; }): Promise; /** * Fully reset a session's live and persisted Copilot state. * Used when the stored transcript/session state becomes unusable and the * runtime must recreate a fresh Copilot session for lossy replay. */ resetSessionState(sessionId: string, options?: { lockHeld?: boolean; }): Promise; /** * Checkpoint session state without destroying the session or * releasing affinity. Used for crash resilience — session stays warm. */ checkpoint(sessionId: string, options?: { lockHeld?: boolean; }): Promise; /** List all in-memory session IDs on this node. */ activeSessionIds(): string[]; /** Final worker cleanup, after the durable runtime has drained. */ shutdown(): Promise; /** * Resolve tools from per-session config + worker-level registry. * Per-session tools take precedence over registry tools with the same name. * * `preferredPackageId` is the package copy this session's bound agent * resolved to. On a tool-name collision between two enabled packages * (scope shadowing publishes the same tool name twice), the session gets * ITS copy's handler instead of whichever package loaded last. Deployment * (static) tools still win every collision. */ private _resolveTools; /** * Resolve the provider config for a given model. * Prefers ModelProviderRegistry, falls back to legacy single provider. */ private _resolveProviderConfig; /** * Build the final system message from: * 1. embedded PilotSwarm framework base * 2. app-level default instructions * 3. bound agent prompt (for named/system sessions) * 4. caller/runtime context */ /** * Fingerprint one dynamic section of the composed system message and * record a `session.prompt_sections` event when it differs from the last * compose for this session. Returns the content unchanged so it can wrap * a section action's return. Best-effort: a CMS write failure is logged * and never fails the compose. */ private _notePromptSection; private _buildKnowledgeToolInstructionsSection; private _buildLastInstructionsSection; /** * The session owner's identity key for agent-copy shadowing, or null when * the session is ownerless/system or the owner is unreadable (fail-safe: * no key means no user-scope copy applies, never the wrong one). * Rides the inspect-viewer TTL cache — one CMS read per session per TTL. */ private _sessionAgentOwnerKey; /** * Who the inspect tools act as, for one session. * * Cached for INSPECT_VIEWER_TTL_MS, not for the session's life: a * privilege value must be able to go stale DOWNWARD promptly. Captured at * creation, it would let a demoted admin keep fleet-wide reach for as long * as they kept a session open; on a short TTL the worst case is bounded by * the TTL. The bound is the point, so it is a named constant, not a magic * number buried in a call. * * ADMIN COMES FROM THE USERS TABLE, not from a token. A worker holds an * owner and never sees a request — cron firings, sub-agent turns, crash * recovery and replay all run turns with no HTTP request behind them at * all — so the portal records the role it authenticated with * (`cms_set_user_role`, migration 0042) and the worker reads that * observation here. * * Two ways it fails closed, both deliberate: * - No recorded role (never signed in, unknown principal, read failure) * is plain user, never admin. * - A role older than ROLE_MAX_AGE_MS is discarded. An observation that * nothing has re-confirmed in half a day is not evidence of current * privilege. */ /** * Who the provider tools act as. * * The cluster Token Manager is machinery and acts with cluster * authority. Every other holder — the personal Token Manager anyone can * run — acts as the SESSION'S OWNER, and the database decides the rest: * the tool list is identical either way, which is the whole point of * putting authority in SQL rather than in a tool registry. */ private _resolveProviderViewer; private _resolveInspectViewer; /** * Store a resolved viewer, sweeping expired entries first when the map has * grown past the sweep threshold. Expiry is by the same TTL the read path * enforces, so a swept entry could never have been served anyway. */ private static _cacheInspectViewer; /** * Is this owner currently an administrator, per the last role the portal * observed for them? * * The decision itself lives in `evaluateRoleObservation` next to the other * shared authz predicates — the same reason `evaluateSessionAccess` moved * there in phase A. A security rule with two implementations has one that * is wrong. */ private _resolveOwnerIsAdmin; private _resolveFeatureViewer; /** * A one-line-per-skill index of the private skills this session's owner * published, or undefined when there are none. Mirrors the wording of the * fleet-wide index so the model treats both the same way. */ private _ownerSkillsIndexSection; private _baseV2CapabilityOwner; /** V2 sees every static and owner-authored skill/workflow without loading its body. */ private _baseV2CapabilityIndexSection; /** * The `load_skill` catalog for ONE session: every shared/deployment skill, * plus the private skills from user-scope packages this session's OWNER * published. A person's own package reaches their own sessions and nobody * else's — the same rule agent copies already follow * (`pickAgentCopyForOwner`). Falls back to the shared list alone when the * session is ownerless, system-owned, or the owner cannot be read: a * failure to identify somebody must never hand out their private skills. */ private _skillCatalogForSession; private _buildSystemMessage; } export {}; //# sourceMappingURL=session-manager.d.ts.map