import { spawnSync } from "node:child_process"; import { workerQuestions, workerSourceLabel, workerSummaryName, type WorkerStatus } from "./background-work.js"; import { renderDecisionLog, type DecisionEvent, type DecisionRecord } from "./decision-log.js"; import { workerResultArtifact, workerResultText } from "./worker-result.js"; import { isSharedSessionTarget, SHARED_TMUX_SESSION } from "./worker-store.js"; import type { CheckpointCommands } from "./checkpoint-commands.js"; import type { CheckpointStore, CheckpointSummary } from "./checkpoint-store.js"; import type { ArtifactCatalog } from "./artifact-catalog.js"; import { storedDeliverableWorkerProjection, type LoadedArtifactContext, type LoadResult } from "./loaded-artifact-context.js"; import type { NavigatorMode } from "./docket-navigator.js"; import type { DocketIntent } from "./docket-command-grammar.js"; import type { Artifact, CheckpointIndexEntry } from "./types.js"; import type { WorkerCommands } from "./worker-commands.js"; import type { WorkerStore } from "./worker-store.js"; import { workerDeliverableArtifact, type WorkerDeliverable } from "./worker-deliverable.js"; import type { DeliverableLifecycle } from "./deliverable-lifecycle.js"; import { describeUnsupportedDeliverable, type DeliverableStore, type StoredDeliverable } from "./deliverable-store.js"; import { findVerdictWorker, runWorkerVerdict, runWorkerVerdictQueue, type DocketVerdictAction } from "./worker-verdict.js"; import type { WorkerChangeReviewOutcome, WorkerChangeReviewPreference } from "./worker-change-review.js"; export type DocketBrowserAction = { action: "inspect" | "openFile" | "promoteWorker" | "reference" | "injectFull" | "copy" | "search" | "tellWorker" | "verdict" | "useDeliverable"; artifact?: Artifact } | { action: "save"; artifact?: Artifact }; export type { DocketVerdictAction } from "./worker-verdict.js"; export type ParallelWorkEntry = { worker: WorkerStatus; artifact: Artifact; }; export type ParallelWorkAction = | { action: "peek"; entry: ParallelWorkEntry } | { action: "details" | "verdict" | "load" | "copyAttach" | "tell" | "stop"; worker: WorkerStatus } | null; export type LoadPickerMode = "checkpoint" | "worker" | "deliverable"; export type LoadPickerSelection = | { kind: "checkpoint"; action: "load" | "preview"; summary: CheckpointSummary } | { kind: "worker"; action: "load"; worker: WorkerStatus } | { kind: "stored-deliverable"; action: "load" | "preview"; deliverable: StoredDeliverable } | null; type NotifyLevel = "info" | "warning" | "error"; type DocketMessageKind = "notice" | "success" | "error" | "usage" | "list" | "action" | "help"; export type DocketCommandRouterDeps = { hasUI: boolean; workerId?: string; projectRoot?: string; workerCommands: WorkerCommands; checkpointCommands: CheckpointCommands; loadedArtifacts: LoadedArtifactContext; workerStore: WorkerStore; checkpointStore: CheckpointStore; deliverableStore?: DeliverableStore; deliverableLifecycle?: DeliverableLifecycle; notify(text: string, level: NotifyLevel): void; emitText(text: string, kind: DocketMessageKind, heading?: string): void; announce(subject: string, detail?: string, kind?: DocketMessageKind): void; docketUsage(advanced?: boolean): string; renderArtifactList(artifacts: Artifact[]): string; renderParallelWorkList(workers: WorkerStatus[], artifactsByWorker: Map, options?: { groupByProject?: boolean }): string; formatArtifact(artifact: Artifact): string; refreshChipWidget(): void; refreshWorkerDockWidget(): Promise; refreshWorkerCarryoverForReview(): Promise; showWorkerResult(worker: WorkerStatus, artifacts: Artifact[], expanded: boolean): void; clearWorkerResult(): boolean; markArtifactDone(artifact: Artifact): void; markWorkerLoaded(worker: WorkerStatus): void; markWorkerUnloaded(worker: WorkerStatus): void; markAllWorkersUnloaded(): void; promoteWorkerChangeSet(artifact: Artifact): Promise; reviewWorkerChangeSet(worker: WorkerStatus, changeSet: Artifact, options: { preferred: WorkerChangeReviewPreference; deliverable?: Pick }): Promise; applyWorkerState(state: "needs_input" | "ready" | "failed", text?: string): Promise; catalog(): Promise; readWorkersWithArtifacts(options?: { allProjects?: boolean }): Promise<{ workers: WorkerStatus[]; artifactsByWorker: Map }>; showParallelWorkDashboard(workers: WorkerStatus[], artifactsByWorker: Map, options?: { groupByProject?: boolean }): Promise; showLoadPicker(summaries: CheckpointSummary[], workers: WorkerStatus[], initialMode: LoadPickerMode, deliverables?: StoredDeliverable[]): Promise; showText(title: string, text: string, options?: { diff?: boolean }): Promise; showDocketBrowser(catalog: ArtifactCatalog, artifacts: Artifact[], initialMode: NavigatorMode): Promise; showVerdict(worker: WorkerStatus, remaining?: number): Promise; showReport(worker: WorkerStatus, deliverable?: WorkerDeliverable): Promise; showArtifact(catalog: ArtifactCatalog, artifact: Artifact): Promise; openFileOrArtifact(catalog: ArtifactCatalog, artifact: Artifact): Promise; input(title: string, placeholder: string): Promise; reviewNote?(title: string, prefill: string): Promise; useDeliverable?(worker: WorkerStatus, deliverable: WorkerDeliverable): Promise; useStoredDeliverable?(deliverable: StoredDeliverable): Promise; saveWorkerDeliverable?(worker: WorkerStatus, deliverable: WorkerDeliverable): Promise; isDeliverableApproved?(deliverable: WorkerDeliverable): Promise; confirmDeleteWorker(worker: WorkerStatus): Promise; confirmDeleteDeliverable?(deliverable: StoredDeliverable): Promise; copyText(text: string): Promise; announceChipChange(artifact: Artifact, mode: "ref" | "full", result: ReturnType): void; parallelKindLabel(kind: Artifact["kind"]): string; /** Append a resolved verdict to the decision ledger. Best-effort; never blocks the verdict. */ recordDecision(record: DecisionRecord): Promise; /** Read the decision ledger for the `/docket log decisions` audit. */ readDecisionEvents(): Promise; }; export type TmuxNavigation = { mode: "attach" | "switch"; target: string; command: string; args: string[]; }; function normalizeTmuxTarget(target: string): { session: string; window?: string } { if (isSharedSessionTarget(target)) { const rawWindow = target.slice(`${SHARED_TMUX_SESSION}:`.length); const window = rawWindow.replace(/^:+/, ""); return { session: SHARED_TMUX_SESSION, ...(window ? { window } : {}) }; } return { session: target }; } export function buildTmuxNavigation(target: string, options: { insideTmux?: boolean } = {}): TmuxNavigation { const insideTmux = options.insideTmux ?? Boolean(process.env.TMUX); const normalized = normalizeTmuxTarget(target); const targetLabel = normalized.window ? `${normalized.session}:${normalized.window}` : normalized.session; if (insideTmux) { return { mode: "switch", target: targetLabel, command: `tmux switch-client -t ${targetLabel}`, args: ["switch-client", "-t", targetLabel], }; } if (normalized.session === SHARED_TMUX_SESSION && normalized.window) { return { mode: "attach", target: targetLabel, command: `tmux attach -t ${SHARED_TMUX_SESSION} \\; select-window -t ${normalized.window}`, args: ["attach", "-t", SHARED_TMUX_SESSION, ";", "select-window", "-t", normalized.window], }; } return { mode: "attach", target: targetLabel, command: `tmux attach -t ${targetLabel}`, args: ["attach", "-t", targetLabel], }; } export function buildAttachCommand(target: string, options: { insideTmux?: boolean } = {}): string { return buildTmuxNavigation(target, options).command; } function runTmuxNavigation(nav: TmuxNavigation): boolean { if (nav.mode !== "switch") return false; const result = spawnSync("tmux", nav.args, { stdio: "ignore" }); return result.status === 0; } function docketMetaString(artifact: Artifact, key: string): string | undefined { const value = artifact.meta?.[key]; return typeof value === "string" && value.length > 0 ? value : undefined; } function artifactWorkerRef(artifact: Artifact): string | undefined { const label = artifact.meta?.workerLabel; if (typeof label === "string" && label.length > 0) return label; return artifact.source; } function loadResultSubject(result: LoadResult): string { const slot = result.slot; return `loaded ${slot.slot} · ${slot.artifacts.length} artifact${slot.artifacts.length === 1 ? "" : "s"}`; } function loadResultDetail(result: LoadResult): string { const slot = result.slot; if (result.source.kind === "worker") return `${workerSummaryName(result.source.worker)}\nrefs: @${slot.slot}.`; if (result.source.kind === "deliverable") return `${result.source.deliverable.ref}\nreviewed deliverable\nrefs: @${slot.slot}.`; if (result.source.kind === "stored-deliverable") return `${result.source.deliverable.ref}\ndurable deliverable\nrefs: @${slot.slot}.`; const checkpoint = result.source.checkpoint; const tag = result.queuedConsume ? "legacy bundle · consume on session end" : "legacy bundle"; return `${checkpoint.id}\n${tag}\nrefs: @${slot.slot}.`; } export function createDocketCommandRouter(deps: DocketCommandRouterDeps) { const announceLoadResult = (result: LoadResult): void => deps.announce(loadResultSubject(result), loadResultDetail(result), "success"); const explicitlyLoadWorker = async (worker: WorkerStatus): Promise => { const deliverable = await deps.workerStore.readCurrentDeliverable?.(worker); const result = await deps.loadedArtifacts.loadSource(deliverable ? { kind: "deliverable", worker, deliverable } : { kind: "worker", worker }); deps.markWorkerLoaded(worker); announceLoadResult(result); await deps.refreshWorkerDockWidget(); return result; }; const explicitlyUnloadWorker = async (worker: WorkerStatus): Promise => { const removed = deps.loadedArtifacts.unloadSource("worker", worker.id); deps.markWorkerUnloaded(worker); if (removed) deps.announce(`unloaded ${removed.slot}`, workerSummaryName(worker)); else deps.notify("Docket worker not loaded", "warning"); await deps.refreshWorkerDockWidget(); }; const explicitlyLoadStoredDeliverable = async (deliverable: StoredDeliverable): Promise => { const result = await deps.loadedArtifacts.loadSource({ kind: "stored-deliverable", deliverable, worker: storedDeliverableWorkerProjection(deliverable) }); announceLoadResult(result); return result; }; const navigateTmux = async (target: string): Promise => { const nav = buildTmuxNavigation(target); if (nav.mode === "switch" && runTmuxNavigation(nav)) { deps.notify(`Switched tmux client: ${nav.command}`, "info"); return; } const copied = await deps.copyText(nav.command); deps.notify(copied ? `Copied: ${nav.command}` : nav.command, copied ? "info" : "warning"); }; const showWorkerResult = async (ref: string, action: "show" | "use"): Promise => { const worker = await deps.workerStore.find(ref); if (!worker) { deps.notify("Docket worker not found", "error"); return; } if (action === "show") { const deliverable = await deps.workerStore.readCurrentDeliverable?.(worker); const artifacts = deliverable ? [workerDeliverableArtifact(deliverable)] : await deps.workerStore.readArtifacts(worker.id); if (deps.hasUI) deps.showWorkerResult(worker, artifacts, true); else deps.emitText(workerResultText(worker, artifacts, 8, deliverable), "list", `docket · ${workerSourceLabel(worker)}`); return; } const result = await explicitlyLoadWorker(worker); const artifact = workerResultArtifact(worker, result.slot.artifacts); if (!artifact) { deps.notify(`No result yet for ${workerSourceLabel(worker)}`, "warning"); return; } const chipResult = deps.loadedArtifacts.toggleChip(artifact, "ref"); deps.refreshChipWidget(); deps.showWorkerResult(worker, result.slot.artifacts, false); deps.announceChipChange(artifact, "ref", chipResult); }; const tellWorker = async (ref: string, text?: string, artifact?: Artifact): Promise => { const trimmed = text?.trim(); if (trimmed) { await deps.workerCommands.tell(ref, trimmed); await deps.refreshWorkerDockWidget(); return; } if (!deps.hasUI) { deps.notify("Usage: /docket tell w ", "error"); return; } const worker = await deps.workerStore.find(ref); const label = worker ? workerSourceLabel(worker) : ref; const questions = worker ? workerQuestions(worker).map((question, index) => `${index + 1}. ${question.text}`).join("\n") : undefined; const placeholder = artifact ? docketMetaString(artifact, "question") ?? artifact.title : questions; const message = (await deps.input(`Tell ${label}`, placeholder ?? "instruction, answer, or follow-up"))?.trim(); if (!message) return; await deps.workerCommands.tell(ref, message); await deps.refreshWorkerDockWidget(); }; return { async handle(intent: DocketIntent): Promise { if (intent.kind === "help") { deps.emitText(deps.docketUsage(intent.advanced === true), "help", intent.advanced === true ? "docket · help advanced" : "docket · help"); return; } if (intent.kind === "clear") { const had = deps.loadedArtifacts.clearChips(); deps.refreshChipWidget(); const hadWorkerResult = deps.clearWorkerResult(); deps.notify(had || hadWorkerResult ? "Docket cleared" : "Docket had no chips", "info"); return; } if (intent.kind === "tell") { await tellWorker(intent.worker, intent.text); return; } if (intent.kind === "verdict") { const worker = await findVerdictWorker(deps, intent.worker); if (!worker) { deps.notify("Docket worker needing verdict not found", "warning"); return; } if (intent.worker) await runWorkerVerdict(deps, worker); else await runWorkerVerdictQueue(deps, worker); return; } if (intent.kind === "decisions") { const events = await deps.readDecisionEvents(); const report = renderDecisionLog(events); if (deps.hasUI) await deps.showText("docket · decisions", report); else deps.emitText(report, "list", "docket · decisions"); return; } if (intent.kind === "attach") { let target = `${SHARED_TMUX_SESSION}:`; if (intent.worker?.toLowerCase() === "parent") { if (!deps.workerId) { deps.notify("Docket attach parent only works inside a Docket worker", "warning"); return; } const worker = await deps.workerStore.find(deps.workerId); const parentTarget = worker?.parentTmuxTarget; if (!parentTarget) { deps.notify("Docket parent tmux target not recorded for this worker", "warning"); return; } target = parentTarget; } else if (intent.worker) { const worker = await deps.workerStore.find(intent.worker); if (!worker) { deps.notify("Docket worker not found", "error"); return; } target = worker.tmuxSession; } await navigateTmux(target); return; } if (intent.kind === "worker-state") { if (!deps.workerId) { deps.notify("Worker state commands only run inside a Docket worker", "warning"); return; } await deps.applyWorkerState(intent.state, intent.text); return; } if (intent.kind === "save") { if (deps.deliverableLifecycle) await deps.deliverableLifecycle.save(intent.source); else deps.notify("Docket deliverable saving is unavailable in this runtime; legacy bundle writes are disabled.", "error"); return; } if (intent.kind === "delete") { if (intent.targetKind === "worker") { await deps.workerCommands.delete(intent.target); await deps.refreshWorkerDockWidget(); } else if (deps.deliverableStore) { const deliverable = await deps.deliverableStore.find(intent.target ?? "last"); if (deliverable) { if (!deps.hasUI || await (deps.confirmDeleteDeliverable?.(deliverable) ?? Promise.resolve(true))) { deps.loadedArtifacts.unloadSource("deliverable", deliverable.ref); await deps.deliverableStore.delete(deliverable); deps.notify(`Docket deliverable deleted: ${deliverable.ref}`, "info"); } } else if (intent.targetKind === "deliverable") deps.notify("Docket deliverable not found", "error"); else await deps.checkpointCommands.delete(intent.target); } else await deps.checkpointCommands.delete(intent.target); return; } if (intent.kind === "list") { if (intent.workers === true) await deps.workerCommands.list({ allProjects: intent.allProjects === true }); else if (deps.deliverableStore) { const deliverables = await deps.deliverableStore.list(); const unsupported = await deps.deliverableStore.listUnsupported(); const legacy = await deps.checkpointStore.list({ includeConsumed: intent.includeConsumed === true }); const lines = [ ...deliverables.map((item) => `${item.ref}\tdeliverable\t${item.source.kind === "worker" ? item.source.workerLabel : "parent"}\t${item.summary}`), ...unsupported.map((item) => `${item.ref}\tdeliverable:unreadable\t${describeUnsupportedDeliverable(item)}\t${item.file}`), ...legacy.map((item) => `${item.id}\tlegacy bundle${item.consumedAt ? ":consumed" : ""}\t${item.cwd}\t${item.note ?? ""}`), ]; deps.emitText(lines.length ? lines.join("\n") : "No Docket deliverables or legacy bundles", "list", "docket · deliverables"); } else await deps.checkpointCommands.list(intent.includeConsumed === true); return; } if (intent.kind === "spawn") { await deps.workerCommands.spawn(intent.task, { ...(intent.worktree ? { worktree: true } : {}), ...(intent.fresh ? { fresh: true } : {}), ...(intent.seed ? { seed: true } : {}), ...(intent.as ? { as: intent.as } : {}), ...(intent.model ? { model: intent.model } : {}), ...(intent.thinking ? { thinking: intent.thinking } : {}), }); await deps.refreshWorkerDockWidget(); return; } if (intent.kind === "kinds") { await deps.workerCommands.listKinds(); return; } if (intent.kind === "respawn") { await deps.workerCommands.respawn(intent.target); await deps.refreshWorkerDockWidget(); return; } if (intent.kind === "workers") { const { workers, artifactsByWorker } = await deps.readWorkersWithArtifacts({ allProjects: intent.allProjects === true }); const groupByProject = intent.allProjects === true; if (!deps.hasUI) { deps.emitText(deps.renderParallelWorkList(workers, artifactsByWorker, { groupByProject }), "list", "docket · parallel work"); return; } while (true) { const result = await deps.showParallelWorkDashboard(workers, artifactsByWorker, { groupByProject }); if (!result) return; if (result.action === "peek") { await deps.showText(`${workerSourceLabel(result.entry.worker)} · ${deps.parallelKindLabel(result.entry.artifact.kind)}`, deps.formatArtifact(result.entry.artifact)); continue; } if (result.action === "details") { await deps.showText(`${workerSourceLabel(result.worker)} · details`, workerResultText(result.worker, artifactsByWorker.get(result.worker.id) ?? [])); continue; } if (result.action === "verdict") { await runWorkerVerdict(deps, result.worker); return; } if (result.action === "load") { await explicitlyLoadWorker(result.worker); return; } if (result.action === "copyAttach") { await navigateTmux(result.worker.tmuxSession); return; } if (result.action === "tell") { await tellWorker(workerSourceLabel(result.worker)); return; } if (result.action === "stop") { if (!(await deps.confirmDeleteWorker(result.worker))) return; await deps.workerCommands.delete(workerSourceLabel(result.worker)); await deps.refreshWorkerDockWidget(); return; } } } if (intent.kind === "load") { if (intent.refKind === "worker") { if (!intent.ref) { deps.notify("Usage: /docket load w", "error"); return; } const worker = await deps.workerStore.find(intent.ref); if (!worker) { deps.notify("Docket worker not found", "error"); return; } try { await explicitlyLoadWorker(worker); } catch (err) { deps.notify(`Docket load failed: ${String(err)}`, "error"); } return; } const opts = { includeConsumed: intent.includeConsumed === true }; let source: Parameters[0] | undefined; if (intent.ref) { const deliverable = await deps.deliverableStore?.find(intent.ref); if (deliverable) source = { kind: "stored-deliverable", deliverable, worker: storedDeliverableWorkerProjection(deliverable) }; else { const checkpoint = await deps.checkpointStore.find(intent.ref, opts); if (!checkpoint) { deps.notify("Docket deliverable or legacy bundle not found", "error"); return; } source = { kind: "checkpoint", checkpoint }; } } else { const [summaries, workers, deliverables] = await Promise.all([ deps.checkpointStore.listSummaries(opts), deps.workerStore.list({ ...(deps.projectRoot ? { projectRoot: deps.projectRoot } : {}) }), deps.deliverableStore?.list() ?? Promise.resolve([]), ]); if (summaries.length === 0 && workers.length === 0 && deliverables.length === 0) { deps.notify("Docket has nothing to load — try /docket save or /docket spawn", "error"); return; } if (!deps.hasUI) { source = deps.loadedArtifacts.defaultLoadSource({ checkpoints: summaries.map((summary) => summary.entry), workers, deliverables }); } else { const initial: LoadPickerMode = deliverables.length > 0 ? "deliverable" : summaries.length > 0 ? "checkpoint" : "worker"; while (true) { const selected = await deps.showLoadPicker(summaries, workers, initial, deliverables); if (!selected) { deps.notify("Docket load cancelled", "info"); return; } if (selected.kind === "worker") { source = { kind: "worker", worker: selected.worker }; break; } if (selected.kind === "stored-deliverable") { if (selected.action === "preview") { await deps.showText(`Docket deliverable ${selected.deliverable.ref}`, selected.deliverable.body); continue; } source = { kind: "stored-deliverable", deliverable: selected.deliverable, worker: storedDeliverableWorkerProjection(selected.deliverable) }; break; } if (selected.action === "preview") { const md = await deps.checkpointStore.readMarkdown(selected.summary.entry); await deps.showText(`Docket legacy bundle ${selected.summary.entry.id}`, md); continue; } source = { kind: "checkpoint", checkpoint: selected.summary.entry }; break; } } } if (!source) return; try { if (source.kind === "worker") { await explicitlyLoadWorker(source.worker); } else if (source.kind === "stored-deliverable") { await explicitlyLoadStoredDeliverable(source.deliverable); } else { const result = await deps.loadedArtifacts.loadSource(source); announceLoadResult(result); } } catch (err) { deps.notify(`Docket load failed: ${String(err)}`, "error"); } return; } if (intent.kind === "unload") { if (intent.targetKind === "all") { const slots = deps.loadedArtifacts.slots().map((entry) => entry.slot); for (const slot of slots) deps.loadedArtifacts.unloadSlot(slot); deps.markAllWorkersUnloaded(); if (slots.length) deps.announce(`unloaded ${slots.length} slot${slots.length === 1 ? "" : "s"}`, slots.join(", ")); else deps.notify("Docket had no loaded slots", "info"); await deps.refreshWorkerDockWidget(); return; } if (intent.targetKind === "worker") { const worker = await deps.workerStore.find(intent.target); if (worker) await explicitlyUnloadWorker(worker); else deps.notify("Docket worker not found", "error"); return; } if (/^d\d+$/i.test(intent.target)) { const removed = deps.loadedArtifacts.unloadSlot(intent.target); if (removed) deps.announce(`unloaded ${removed.slot}`, removed.sourceId); else deps.notify("Docket deliverable not loaded", "warning"); return; } if (deps.deliverableStore) { const deliverable = await deps.deliverableStore.find(intent.target); if (deliverable) { const removed = deps.loadedArtifacts.unloadSource("deliverable", deliverable.ref); if (removed) deps.announce(`unloaded ${removed.slot}`, deliverable.ref); else deps.notify("Docket deliverable not loaded", "warning"); return; } if (intent.targetKind === "deliverable") { deps.notify("Docket deliverable not loaded", "warning"); return; } } const checkpoint = await deps.checkpointStore.find(intent.target, { includeConsumed: true }); const targetId = checkpoint?.id ?? intent.target; const removed = deps.loadedArtifacts.unloadSource("checkpoint", targetId); if (removed) deps.announce(`unloaded ${removed.slot}`, removed.sourceId); else deps.notify("Docket legacy bundle not loaded", "warning"); return; } const shouldBrowse = intent.kind === "browse" || intent.kind === "answers" || intent.kind === "search"; if (shouldBrowse) await deps.refreshWorkerCarryoverForReview(); const catalog = await deps.catalog(); let artifacts = catalog.list(); let initialMode: NavigatorMode = intent.kind === "browse" && intent.mode ? intent.mode : "review"; if (intent.kind === "answers") { initialMode = "answers"; if (intent.query) artifacts = (await catalog.search(intent.query)).filter((artifact) => artifact.kind === "response"); else artifacts = artifacts.filter((artifact) => artifact.kind === "response"); if (artifacts.length === 0) { deps.notify(intent.query ? `Docket answers found no matches for: ${intent.query}` : "Docket has no answers yet", "info"); return; } if (!deps.hasUI) { deps.emitText(deps.renderArtifactList(artifacts), "list", intent.query ? `docket · answers "${intent.query}"` : "docket · answers"); return; } } if (intent.kind === "search") { initialMode = "log"; artifacts = await catalog.search(intent.query); if (artifacts.length === 0) { deps.notify(`Docket search found no artifacts for: ${intent.query}`, "info"); return; } if (!deps.hasUI) { deps.emitText(deps.renderArtifactList(artifacts), "list", `docket · search "${intent.query}"`); return; } } if (intent.kind === "artifact") { const artifact = catalog.find(intent.idOrRef); if (!artifact) { deps.notify("Docket artifact not found", "error"); return; } deps.markArtifactDone(artifact); if (intent.action === "ref") { const r = deps.loadedArtifacts.toggleChip(artifact, "ref"); deps.refreshChipWidget(); deps.announceChipChange(artifact, "ref", r); } else if (intent.action === "inject-full") { const r = deps.loadedArtifacts.toggleChip(artifact, "full"); deps.refreshChipWidget(); deps.announceChipChange(artifact, "full", r); } else { const ok = await deps.copyText(catalog.fullText(artifact)); deps.notify(ok ? `Docket copied ${artifact.id}` : "No clipboard command found", ok ? "info" : "warning"); } return; } if (!deps.hasUI) { deps.emitText(deps.renderArtifactList(artifacts), "list", `docket · ${initialMode}`); return; } while (true) { const result = await deps.showDocketBrowser(catalog, artifacts, initialMode); if (!result) return; if (result.action === "save") { if (deps.deliverableLifecycle && result.artifact) await deps.deliverableLifecycle.saveArtifact(result.artifact.ref); else if (deps.deliverableLifecycle) await deps.deliverableLifecycle.save(); else deps.notify("Docket deliverable saving is unavailable in this runtime; legacy bundle writes are disabled.", "error"); return; } if (result.action === "search") { const query = (await deps.input("Search Docket", "commands, errors, files, answers..."))?.trim(); if (!query) continue; const matches = await catalog.search(query); if (matches.length === 0) { deps.notify(`Docket search found no artifacts for: ${query}`, "info"); continue; } artifacts = matches; initialMode = "log"; continue; } if (result.action === "tellWorker" && result.artifact) { const workerRef = artifactWorkerRef(result.artifact); if (!workerRef) { deps.notify("Docket worker not found for this item", "error"); continue; } await tellWorker(workerRef, undefined, result.artifact); return; } if (result.action === "verdict" && result.artifact) { const workerId = docketMetaString(result.artifact, "workerId") ?? artifactWorkerRef(result.artifact); const worker = workerId ? await findVerdictWorker(deps, workerId) : undefined; if (!worker) { deps.notify("Docket worker not found for this item", "error"); continue; } await runWorkerVerdict(deps, worker); return; } if (!result.artifact) return; if (result.action === "useDeliverable") { const deliverable = await deps.deliverableStore?.find(result.artifact.ref); if (deliverable && deps.useStoredDeliverable) await deps.useStoredDeliverable(deliverable); else deps.notify("Docket stored deliverable not found", "error"); return; } deps.markArtifactDone(result.artifact); if (result.action === "inspect") { await deps.showArtifact(catalog, result.artifact); continue; } if (result.action === "openFile") { await deps.openFileOrArtifact(catalog, result.artifact); continue; } if (result.action === "promoteWorker") { if (await deps.promoteWorkerChangeSet(result.artifact)) deps.markArtifactDone(result.artifact); return; } const artifact = result.artifact; if (result.action === "reference") { const r = deps.loadedArtifacts.toggleChip(artifact, "ref"); deps.refreshChipWidget(); deps.announceChipChange(artifact, "ref", r); } else if (result.action === "injectFull") { const r = deps.loadedArtifacts.toggleChip(artifact, "full"); deps.refreshChipWidget(); deps.announceChipChange(artifact, "full", r); } else if (result.action === "copy") { const ok = await deps.copyText(catalog.fullText(artifact)); deps.notify(ok ? `Docket copied ${artifact.id}` : "No clipboard command found", ok ? "info" : "warning"); } return; } }, }; }