import type { JamDeps } from "../deps.js"; import type { FullIssueContext } from "../domain/context.js"; import type { ExistingIssueOperation, FieldUpdateInput, WriteInput, WritePlan, WritePlanReceipt } from "../domain/write.js"; export type PlanWriteRequest = { /** Absent for `issue.create`, which names a project rather than an issue. */ key?: string; operation: string; input: Record; }; /** * Work out whether a requested change is currently possible, and describe it. * * Reads only. Nothing here mutates Jira, and that is the whole point of the * step: the agent gets to see what the issue looks like now, what JAM would * do to it, and what a direct read will have to show before JAM will call it * done - all before anything has happened. * * The order matters. Scope and operation are checked before any Jira call, so * an out-of-scope key costs nothing and comes back as a JAM refusal rather * than a 404. Everything after that is derived from the issue as Jira reports * it right now, never from what the caller asserted about it. */ export declare function planWrite(deps: JamDeps, request: PlanWriteRequest): Promise<{ plan: WritePlan; receipt: WritePlanReceipt; }>; /** * The issue as Jira has it, read directly by key. * * `getIssue`, not `getIssues`: ConsistencyPolicy requires a direct issue GET * for anything that decides or confirms a write, and the bulk endpoint is not * one. A JQL result can lag behind the issue it describes; a bulk fetch is * free to answer from a different path than the single-issue endpoint. Neither * difference matters for ordinary reads, and both matter here. * * The one read every write goes through - the pre-write conflict check, the * post-write confirmation, and the post-create confirmation. */ export type IssueSnapshot = { issue: FullIssueContext; /** * The issue's canonical Jira id, carried separately because the write plane * requires it and the read shape only offers it. * * A key is a locator: Jira can move one between issues, and an integration * that recorded a key months ago is holding a string, not a target. Every * write is pinned to this instead - planned against it, re-checked against * it before the mutation, and confirmed against it afterwards. */ issueId: string; /** Identity of the current assignee, which `issue.assignee` cannot supply. */ assigneeAccountId?: string; }; export declare function readIssue(deps: JamDeps, issueKey: string): Promise; /** * Check the request against the contract, and normalize it. * * Pure: no Jira, no state. Whether an operation is supported, whether a field * is writable and whether the input is even the right shape are all knowable * without asking Jira anything, so they are answered first. */ export declare function validateInput(operation: ExistingIssueOperation, raw: Record): WriteInput; /** Whitelisted values to the shapes Jira's field API expects. */ /** Exported so apply can derive the same fields again and compare. */ export declare function toJiraFields(input: FieldUpdateInput): Record;