/** * Types shared by job producers, the registry, and controllers. The * service implementation lives in `./index.ts`. * @module @deepseek-ai/dsh-jobs/types */ import type { Agent } from '@deepseek-ai/dsh-agent'; import type { SessionId } from '@deepseek-ai/dsh-session'; import type { JobId } from './brand.ts'; export { JobId } from './brand.ts'; /** * Task lifecycle: `running`, optionally `stopping`, then exactly one terminal * status. Producer-specific facts belong in {@link JobSnapshot.detail}. */ export type JobStatus = 'running' | 'stopping' | 'completed' | 'killed' | 'failed'; /** * Producer-defined job kinds. Plugins extend this map by declaration merging; * the registry treats every value as an opaque id namespace. */ export interface JobKindMap { bash: 'bash'; subagent: 'subagent'; } /** The merge-extensible union of registered producer kind names. */ export type JobKind = JobKindMap[keyof JobKindMap]; /** Terminal result supplied by a producer through {@link JobHooks.done}. */ export interface JobOutcome { /** How the job ended: finished (`completed`), cancelled (`killed`), or broke (`failed`). */ status: 'completed' | 'killed' | 'failed'; /** Kind-specific detail rendered into status lines ('exit code: 3', 'max-tokens'). */ detail?: string; /** Final output for jobs without `readOutput`; stream jobs leave it unset. */ output?: string; } /** * Producer declaration passed to {@link JobRegistry.start}. The runtime * preflights access and cleanup before invoking {@link run}; the producer owns * execution resources while the runtime owns identity and lifecycle state. */ export interface JobStart { /** Producer kind — also the id prefix (`bash`, `subagent`, …). */ kind: JobKind; /** One-line model-facing label (the command; the delegation description). */ label: string; /** * Optional UTF-8 byte cap for each complete model-facing completion notice or * output read, including controller status metadata. */ outputLimitBytes?: number; /** * Owning live agent. Access is fenced by its session id, and agent disposal * cancels and awaits the job. The instance must be the one currently * registered under its agent id. Omitting the owner creates an unowned job, * open to any caller until service disposal. */ owner?: Agent; /** * Start the work after preflight and synchronously return its hooks. Called * once; a throw leaves nothing registered, and the producer must clean up any * partially started resources. */ run(): JobHooks; } /** Hooks through which the runtime controls and observes producer work. */ export interface JobHooks { /** * Request termination. Must be synchronous, idempotent, and eventually settle * {@link done}; throws propagate. The optional reason is forwarded verbatim. */ cancel(reason?: string): void; /** * Resolves after the producer releases its resources, not merely when work * finishes. Must not reject; the runtime converts a rejection to `failed`. * If teardown cancellation throws, the runtime may force-fail only the * registry record without claiming that the work stopped. */ done: Promise; /** * Consume output produced since the previous call. The producer formats * truncation and spill notices. Absence marks a final-output-only job; each * job has one consuming cursor. */ readOutput?(): string; } /** * A read-only projection of one job, safe to hand to listeners and tools — * a fresh object per call, never live registry state. */ export interface JobSnapshot { /** The registry-issued id (`-N`). */ id: JobId; /** The producer kind the job was registered with. */ kind: JobKind; /** The producer-supplied one-line label. */ label: string; /** Producer-owned cap for complete model-facing notices and output reads. */ outputLimitBytes?: number; /** * Owner session id used for authorization and correlation; absent for * unowned jobs. Completion listeners receive the exact {@link Agent} * separately through {@link JobDoneListener}. */ ownerSession?: SessionId; /** Current lifecycle state. */ status: JobStatus; /** Kind-specific status detail, present once the producer supplied one (usually terminal). */ detail?: string; /** Epoch ms when the job was registered. */ startedAt: number; /** Epoch ms when the job settled; absent while `running`/`stopping`. */ finishedAt?: number; /** * True when a kill, read, wait, or teardown cancel has reported or committed * to report the terminal state. Completion reporters suppress redundant * notices when set. Teardown claims it because the owner or service being * destroyed leaves no reader: a reporter that opens a turn on notice would * otherwise spend a model request per teardown layer. */ reported: boolean; } /** Output and post-read state returned by {@link JobRegistry.read}. */ export interface JobRead { /** * Stream kinds: the consuming delta since the previous read. Final-output * kinds: empty while live, the terminal {@link JobOutcome.output} (or * empty) once settled — idempotent, never consumed. */ text: string; /** The job's state at read time. */ snapshot: JobSnapshot; } /** * Completion callback with the exact owner supplied at start, or `undefined` * for an unowned job. Returned promises are observed but not awaited. */ export type JobDoneListener = (snapshot: JobSnapshot, owner: Agent | undefined) => void | PromiseLike; /** * Observation callback for a change to what one owner's {@link JobRegistry.list} * would return. It is owner-granular rather than job-granular because the * change may be a removal, which no per-job record can express, and because * its consumers re-read the whole visible set anyway. * * An `undefined` owner means an unowned job changed, so every caller's visible * set changed with it. */ export type JobsChangedListener = (owner: Agent | undefined) => void; //# sourceMappingURL=types.d.ts.map