/**
 * The providerless, executor-less, UI-less agent spine as ONE bundle plugin.
 *
 * Loads the fixed set of services every harness agent needs — `timer`, the LLM
 * service, the session store, system-prompt assembly, the tool registry, the
 * agent registry, the dev-mode invariants, the model-facing `bash` tool
 * schemas, and the concrete `agent-loop` — and forwards the loop's `agents`
 * list as its OWN config (default `[]`), so each app supplies its own
 * pre-created agents.
 *
 * It is deliberately NOT the whole app: the swappable choices stay OUTSIDE the
 * bundle, picked by whatever loads it.
 *  - the LLM ADAPTER (`llm-deepseek`/`llm-pi-ai`/`llm-replay`) — the bundle
 *    ships the abstract `llm` service + `tool-bash` consumer schema; the leaf
 *    registers a concrete adapter on `ctx.llm`.
 *  - the bash EXECUTOR (`bash-local` or a sandboxed impl) — the bundle ships
 *    the `bash` tool consumer; the leaf provides `ctx.bash`.
 *  - the PRESENTATION (stdio UI / ACP bridge / a logger) and the per-app infra
 *    (a console logger, `hmr`) — these are the coupled "front-door cluster" the
 *    app packages ({@link @deepseek-ai/dsh-stdio-agent},
 *    {@link @deepseek-ai/dsh-acp-agent}) bake in, NOT the shared spine.
 *
 * This is the interface/implementation/consumer seam at the composition level:
 * the bundle owns the shared spine, the leaf owns the backends, the app package
 * owns the front door. `timer` is in the spine (common to every front door — it
 * writes nothing to stdout); the console logger is NOT (it writes to stdout,
 * which the ACP bridge reserves for its JSON-RPC channel).
 *
 * Services register in the root store keyed by their isolate symbol, so a child
 * loaded here via `ctx.plugin(...)` is visible to the bundle's SIBLINGS (the
 * leaf's adapter and executor) exactly as a nested `plugin-include` subtree's
 * services were before this bundle existed — cordis gates every read on
 * `inject`, never on load order, so the fixed child set resolves regardless of
 * which entry loads first.
 *
 * Plugin export shape: named `name`/`Config`/`apply`, NO default export — the
 * cordis Loader's `unwrapExports` does `exports.default ?? exports`, so a stray
 * default would collapse the module to the bare `apply` function and drop the
 * `Config` schema (see docs/postmortem/0001). The keyless Loader-path smokes in
 * the app packages guard this end-to-end.
 *
 * @module @deepseek-ai/dsh-agent-core
 */

import type { Context } from 'cordis'
import Timer from '@cordisjs/plugin-timer'
import LlmService from '@deepseek-ai/dsh-llm'
import SessionStore from '@deepseek-ai/dsh-session'
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
import ToolRegistry from '@deepseek-ai/dsh-tools'
import AgentRegistry from '@deepseek-ai/dsh-agent'
import * as invariants from '@deepseek-ai/dsh-invariants'
import * as toolBash from '@deepseek-ai/dsh-tool-bash'
import AgentLoop, { type Config as AgentLoopConfig } from '@deepseek-ai/dsh-agent-loop'

export const name = 'agent-core'

/**
 * Bundle config: the agent-loop `agents` list, forwarded verbatim. Default `[]`
 * — an app that pre-creates no agents (the ACP bridge creates them on demand at
 * `session/new`) simply omits it; an app that needs a pre-created `main` (the
 * stdio chat) supplies one. This IS {@link AgentLoopConfig}, so the schema and
 * the forwarded shape can never drift.
 */
export type Config = AgentLoopConfig

/** Forward the loop's own schema so validation + defaulting stay identical. */
export const Config = AgentLoop.Config

/**
 * Load the spine. Each `ctx.plugin(...)` mounts one child of the bundle fiber;
 * `agent-loop` receives the forwarded `agents` list. Load order is irrelevant
 * (cordis pends each fiber on its `inject` until the services it needs exist),
 * but the listing mirrors the dependency layering for readability: the LLM
 * vocabulary and core registries first, then the dev tripwire and the bash tool
 * consumer, then the loop that drives them.
 */
export function apply(ctx: Context, config: Config): void {
  ctx.plugin(Timer)
  ctx.plugin(LlmService)
  ctx.plugin(SessionStore)
  ctx.plugin(SystemPrompt)
  ctx.plugin(ToolRegistry)
  ctx.plugin(AgentRegistry)
  ctx.plugin(invariants)
  ctx.plugin(toolBash)
  ctx.plugin(AgentLoop, { agents: config.agents })
}
