import type { ExternalWorkItemSource } from '../storage/domains/work-items/base.js'; export type WorkItemSource = 'github-issue' | 'github-pr' | 'gitlab-issue' | 'gitlab-pr' | 'linear-issue' | 'jira-issue' | 'incidentio-follow-up' | 'manual'; export declare function externalSourceForWorkItem(source: WorkItemSource, sourceKey: string, url?: string): ExternalWorkItemSource; /** The source label that holds an issue at rest until a maintainer decides; compared lowercased. */ export declare const NEEDS_APPROVAL_LABEL = "status: needs approval"; export declare const AUTO_TRIAGED_LABEL = "status: auto-triaged"; export declare function needsApproval(item: { metadata: Record | null; stages?: readonly string[]; acceptedAt?: Date | string | null; }): boolean; export declare function workItemSource(source: ExternalWorkItemSource | null): WorkItemSource; export declare function externallyAuthored(item: { source: string; metadata: Record | null; }): boolean; export declare function knownExternalAuthor(item: { source: string; metadata: Record | null; }): boolean; export declare function externallyAuthoredWorkItem(item: { externalSource: ExternalWorkItemSource | null; metadata: Record | null; }): boolean; export declare const FACTORY_RULE_STAGES: readonly ["intake", "triage", "planning", "execute", "review", "done", "canceled"]; export type FactoryRuleStage = (typeof FACTORY_RULE_STAGES)[number] | (string & {}); export declare const FACTORY_ROLE_STAGES: { readonly triage: "triage"; readonly plan: "planning"; readonly work: "execute"; readonly review: "review"; }; export type FactoryRole = keyof typeof FACTORY_ROLE_STAGES; export declare function isFactoryRole(value: string): value is FactoryRole; export declare const FACTORY_TRIAGE_TYPES: readonly ["bug", "feature request", "docs", "question/support", "maintenance", "duplicate", "resolved", "invalid", "spam", "out-of-scope", "other"]; export type FactoryTriageType = (typeof FACTORY_TRIAGE_TYPES)[number]; export declare function isFactoryTriageType(value: unknown): value is FactoryTriageType; export declare function isFactoryRuleStage(value: unknown): value is FactoryRuleStage; export declare function factoryRuleStage(stages: readonly string[]): FactoryRuleStage | undefined; export declare function isTerminalFactoryRuleStage(stages: readonly string[]): boolean; /** Working lanes hold cards with a seat engaged; Intake, Done and Canceled rest them. */ export declare function isWorkingFactoryRuleStage(stage: FactoryRuleStage): boolean; export declare function factoryLaneForRole(role: string): FactoryRuleStage | undefined; export declare const FACTORY_RULE_BOARDS: readonly ["work", "review"]; export type FactoryRuleBoard = (typeof FACTORY_RULE_BOARDS)[number] | (string & {}); export declare const FACTORY_RULE_SOURCES: readonly ["issue", "pullRequest", "gitlabIssue", "gitlabPullRequest", "linearIssue", "jiraIssue", "incidentioFollowUp", "manual"]; export type FactoryRuleSource = (typeof FACTORY_RULE_SOURCES)[number]; export declare const FACTORY_GITHUB_EVENTS: readonly ["issueOpened", "issueEdited", "issueClosed", "issueCommentCreated", "issueCommentEdited", "issueCommentDeleted", "pullRequestOpened", "pullRequestUpdated", "pullRequestCommentCreated", "pullRequestReviewRequested", "pullRequestReviewSubmitted", "pullRequestMerged", "pullRequestClosed"]; export type FactoryGithubEventName = (typeof FACTORY_GITHUB_EVENTS)[number]; export declare const FACTORY_GITLAB_EVENTS: readonly ["issueOpened", "issueUpdated", "issueClosed", "issueCommented", "mergeRequestOpened", "mergeRequestUpdated", "mergeRequestCommented", "mergeRequestMerged", "mergeRequestClosed"]; export type FactoryGitLabEventName = (typeof FACTORY_GITLAB_EVENTS)[number]; export declare const FACTORY_LINEAR_EVENTS: readonly ["issueObserved", "issueClosed"]; export type FactoryLinearEventName = (typeof FACTORY_LINEAR_EVENTS)[number]; export declare const FACTORY_JIRA_EVENTS: readonly ["issueObserved", "issueClosed"]; export type FactoryJiraEventName = (typeof FACTORY_JIRA_EVENTS)[number]; export declare const FACTORY_INCIDENTIO_EVENTS: readonly ["followUpObserved", "followUpClosed"]; export type FactoryIncidentioEventName = (typeof FACTORY_INCIDENTIO_EVENTS)[number]; export type FactoryRuleJsonValue = null | boolean | number | string | FactoryRuleJsonValue[] | { [key: string]: FactoryRuleJsonValue; }; export interface FactoryRuleItemContext { id: string; source: WorkItemSource; sourceKey: string | null; parentWorkItemId: string | null; title: string; url: string | null; stages: readonly string[]; acceptedAt: Date | null; /** Intake-stamped facts about the source — repository id, reporter login, labels. */ metadata: Record | null; } export type FactoryRuleActor = { type: 'human'; id: string; } | { type: 'agent'; bindingId: string; role: string; } | { type: 'github'; login: string; trusted: boolean; factoryAuthored: boolean; } | { type: 'gitlab'; username: string; trusted: boolean; factoryAuthored: boolean; } | { type: 'system'; id: string; }; export interface FactoryRuleIngressIdentity { type: 'human' | 'agent' | 'toolResult' | 'github' | 'gitlab' | 'linear' | 'jira' | 'incidentio' | 'rule'; id: string; } export interface FactoryRuleCausalEntry { ingressId: string; decisionType: FactoryCommitDecision['type']; } /** The phase a card sits in, as its board declares it. */ export interface FactoryRulePhaseContext { id: string; kind: 'resting' | 'working' | 'terminal'; /** Seat carrying a working phase; absent for resting and terminal phases. */ role?: string; /** Outcome names the phase declares, e.g. `approved` or `canceled`; empty when it declares none. */ outcomes: readonly string[]; } export interface FactoryRuleContextBase { tenant: { orgId: string; projectId: string; }; actor: FactoryRuleActor; ingress: FactoryRuleIngressIdentity; cause: string; causalChain: readonly FactoryRuleCausalEntry[]; configVersion: string; } export interface FactoryBoundRuleContext extends FactoryRuleContextBase { item: FactoryRuleItemContext; board: FactoryRuleBoard; itemRevision: number; } export interface FactoryStageRuleContext extends FactoryBoundRuleContext { source: FactoryRuleSource; stage: FactoryRuleStage; fromStage: FactoryRuleStage; toStage: FactoryRuleStage; } export interface FactoryToolResultRuleContext extends FactoryBoundRuleContext { toolName: string; threadId: string; assistantMessageId: string; toolCallId: string; result: { status: 'success' | 'error'; value: FactoryRuleJsonValue; }; } export interface FactoryGithubRuleContext extends FactoryRuleContextBase { item?: FactoryRuleItemContext; board?: FactoryRuleBoard; itemRevision?: number; /** Where the card's board sends it when its tracked source closes. */ boardClosure?: FactoryRuleBoardClosure; /** What the card's current phase means on its board; absent without a card or when the board does not declare the phase. */ phase?: FactoryRulePhaseContext; /** * Board an issue's labels route it to, when the project has a matching label route and that board * is installed. Absent for pull requests and for issues whose labels select nothing. */ intake?: FactoryRuleIntakeTarget; /** * Set on the one evaluation per pull request delivery that files the pull * request's own Review card. Opening a pull request concerns two cards — that * Review card and the Work item that authored the pull request — so the rule * answers for the two separately: the arrival carries this flag and is * committed against the authoring item when resolution found one, which is * what links the new card to it, while the authoring item's own evaluation * leaves the flag unset. */ pullRequestIntake?: boolean; event: FactoryGithubEventName; deliveryId: string; factory: { createdAt: string; }; /** `installationId` is the GitHub App installation the delivery arrived through. */ repository: { id: number; fullName: string; installationId?: number; }; issue?: { number: number; title: string; url: string; createdAt?: string; updatedAt?: string; assignees?: string[]; labels?: string[]; state?: 'open' | 'closed'; /** GitHub close reason: `completed`, `not_planned`, or `duplicate`. */ stateReason?: string; }; issueChange?: { title: boolean; body: boolean; }; issueComment?: { id: number; body?: string; url?: string; author?: string; authorType?: string; createdAt?: string; updatedAt?: string; }; pullRequest?: { number: number; title: string; url: string; createdAt?: string; state: 'open' | 'closed'; draft: boolean; merged: boolean; assignees?: string[]; requestedReviewers?: string[]; labels?: string[]; author?: string; factoryAuthored: boolean; headBranch: string; baseBranch: string; }; /** Present on `pullRequestReviewRequested`: who review was (re-)requested from. */ reviewRequest?: { reviewer: string; factoryReviewer: boolean; }; /** Present when a PR comment uses Factory's exact review command. */ reviewCommand?: { command: 'review' | 're-review'; target: string; }; /** Present on `pullRequestReviewSubmitted`: the review that was just posted. */ review?: { id: number; state: string; url: string; author?: string; body?: string; }; } /** * Where an intake source binding says new items from this source should land. * Absent when the source is unbound or bound without a board (built-in routing). */ export interface FactoryRuleIntakeTarget { board: string; initialPhase: string; } /** * Where a source-closed rule moves the card, from the `sourceClosed` mapping its installed board * declares. Absent when the card's board is not installed or declares no mapping. */ export interface FactoryRuleBoardClosure { /** Title of the card's board, for messages. */ boardTitle: string; /** Terminal phase for a source that was completed. */ completed: FactoryRuleBoardClosurePhase; /** Terminal phase for a source that was canceled or not planned. */ canceled: FactoryRuleBoardClosurePhase; /** Whether the card already sits in a terminal phase of its board. */ itemTerminal: boolean; } export interface FactoryRuleBoardClosurePhase { phase: string; title: string; } export interface FactoryGitLabRuleContext extends FactoryRuleContextBase { item?: FactoryRuleItemContext; board?: FactoryRuleBoard; itemRevision?: number; /** Where the card's board sends it when its tracked source closes. */ boardClosure?: FactoryRuleBoardClosure; /** What the card's current phase means on its board; absent without a card or when the board does not declare the phase. */ phase?: FactoryRulePhaseContext; intake?: FactoryRuleIntakeTarget; event: FactoryGitLabEventName; deliveryId: string; factory: { createdAt: string; }; repository: { id: number; fullName: string; host: string; }; issue?: { number: number; sourceKey: string; title: string; url: string; createdAt?: string; updatedAt?: string; assignees?: string[]; labels?: string[]; labelColors?: Record; state?: 'open' | 'closed'; author?: string; authorTrusted: boolean; }; note?: { id: number; body?: string; url?: string; author?: string; createdAt?: string; updatedAt?: string; }; mergeRequest?: { number: number; sourceKey: string; title: string; url: string; createdAt?: string; state: 'open' | 'closed'; draft: boolean; merged: boolean; assignees?: string[]; reviewers?: string[]; labels?: string[]; labelColors?: Record; author?: string; authorTrusted: boolean; factoryAuthored: boolean; headBranch: string; baseBranch: string; }; } export interface FactoryLinearRuleContext extends FactoryRuleContextBase { item?: FactoryRuleItemContext; board?: FactoryRuleBoard; itemRevision?: number; /** Where the card's board sends it when its tracked source closes. */ boardClosure?: FactoryRuleBoardClosure; /** What the card's current phase means on its board; absent without a card or when the board does not declare the phase. */ phase?: FactoryRulePhaseContext; /** Bound board for the source this issue came from, when one is configured and installed. */ intake?: FactoryRuleIntakeTarget; event: FactoryLinearEventName; issue: { id: string; identifier: string; title: string; url: string; state: string; stateType: string; priorityLabel: string; assignee: string | null; creator: string | null; team: string | null; labels: readonly string[]; createdAt: string; updatedAt: string; sourceId?: string | null; projectId?: string | null; }; } export interface FactoryJiraRuleContext extends FactoryRuleContextBase { item?: FactoryRuleItemContext; board?: FactoryRuleBoard; itemRevision?: number; /** Where the card's board sends it when its tracked source closes. */ boardClosure?: FactoryRuleBoardClosure; /** What the card's current phase means on its board; absent without a card or when the board does not declare the phase. */ phase?: FactoryRulePhaseContext; /** Bound board for the source this issue came from, when one is configured and installed. */ intake?: FactoryRuleIntakeTarget; event: FactoryJiraEventName; issue: { /** Stable issue reference — the direct integration's Jira id or the Platform-encoded issue reference. */ id: string; identifier: string; title: string; url: string; state: string; stateType: string; priorityLabel: string; assignee: string | null; author: string | null; project: string | null; site: string | null; labels: readonly string[]; createdAt: string; updatedAt: string; }; } export interface FactoryIncidentioRuleContext extends FactoryRuleContextBase { item?: FactoryRuleItemContext; board?: FactoryRuleBoard; itemRevision?: number; /** Where the card's board sends it when its tracked source closes. */ boardClosure?: FactoryRuleBoardClosure; /** What the card's current phase means on its board; absent without a card or when the board does not declare the phase. */ phase?: FactoryRulePhaseContext; /** Bound board for the source this follow-up came from, when one is configured and installed. */ intake?: FactoryRuleIntakeTarget; event: FactoryIncidentioEventName; issue: { /** Stable item reference — the prefixed incident.io follow-up id the intake feed serves as `id`. */ id: string; identifier: string; title: string; url: string; state: string; stateType: string; priorityLabel: string; assignee: string | null; author: string | null; /** Reference of the incident this follow-up belongs to, when available. */ incident: string | null; labels: readonly string[]; createdAt: string; updatedAt: string; }; } export type FactoryRuleHandler = (context: Readonly) => FactoryRuleDecision | void | Promise; export interface FactoryBoardRuleLeaf { onEnter?: FactoryRuleHandler; onExit?: FactoryRuleHandler; } export type FactoryRuleRejectionCode = 'forbidden' | 'invalid_transition' | 'missing_binding' | 'stale' | 'timeout' | 'rule_error' | 'causal_depth_exceeded' | 'repeated_transition' | 'approval_required'; export interface FactoryRuleRejectDecision { type: 'reject'; code: FactoryRuleRejectionCode; reason: string; } interface FactoryCommitDecisionBase { idempotencyKey: string; } export interface FactoryTransitionDecision extends FactoryCommitDecisionBase { type: 'transition'; board: FactoryRuleBoard; stage: FactoryRuleStage; /** * Delivered to the item's active session (waking it if idle) after the * transition commits. Skipped when the item has no active run binding, so * informational messages never fail the transition. */ message?: { text: string; role?: string; }; /** * Runs the stage's entry rules even when the item is already in that stage. * A transition to the current stage is normally inert, because most callers * are correcting a board into a state it already holds. Re-entry is for the * opposite case: the stage's work is in flight and has been invalidated, so * it has to start over. */ reenter?: boolean; } export interface FactoryUpsertLinkedWorkItemDecision extends FactoryCommitDecisionBase { type: 'upsertLinkedWorkItem'; board: FactoryRuleBoard; source: WorkItemSource; sourceKey: string; /** * Org-wide ownership key for the external record, when one Factory at a time * may hold a live card for it (a stable Linear issue id, for instance). The * store enforces it with a unique index, so a second project's materialization * is refused rather than duplicated. */ claimKey?: string; title: string; url: string | null; stage: FactoryRuleStage; /** * File the card at `stage` as its first entry and run none of the board's * phase rules for it — no arrival, no destination entry. The card is filed * (or, if it already exists, moved) and left parked for a person; nothing is * started for it. For external records that arrive already past the board's * first step: a GitHub issue whose triage is already recorded, for instance. * * Placement is the whole decision. An existing card it reaches is moved to * that stage through the same relocation the label routes use, and its * metadata is left alone. */ skipRules?: boolean; metadata?: Record; } interface FactoryInvokeSkillDecisionBase extends FactoryCommitDecisionBase { type: 'invokeSkill'; role: string; arguments?: string; precedingMessage?: string; cancelInFlight?: boolean; } /** * Starting an agent run. Most runs activate a skill, because the skill carries * the handoff contract later rules match on. A run whose completion is already * signalled some other way — Building finishes by opening a pull request, which * arrives as its own event — needs no contract, so it can carry a plain prompt * instead of an otherwise empty skill. */ export type FactoryInvokeSkillDecision = FactoryInvokeSkillDecisionBase & ({ skillName: string; prompt?: never; /** * Same-stage re-entry: the skill is already active in the card's live session, * so deliver a compact continuation that references it by name and carries only * the fresh arguments, instead of re-pasting the whole skill document. Only valid * for named-skill decisions — a plain prompt run has no active skill to resume. */ resume?: boolean; } | { prompt: string; skillName?: never; resume?: never; }); export interface FactorySendMessageDecision extends FactoryCommitDecisionBase { type: 'sendMessage'; /** Omitted: the card's live session, whichever seat holds it. Required with `prepareBinding`. */ role?: string; message: string; priority?: 'medium' | 'high' | 'urgent'; idleBehavior?: 'persist' | 'wake'; prepareBinding?: boolean; } export interface FactoryNotifyDecision extends FactoryCommitDecisionBase { type: 'notify'; title: string; body?: string; level?: 'info' | 'warning' | 'error'; } /** * Dismisses Factory change requests an approval has superseded on a GitHub * pull request. Only reviews carrying Factory's `Verdict: request changes` * marker from an identity other than the approving one are dismissed. */ export interface FactoryDismissStaleReviewsDecision extends FactoryCommitDecisionBase { type: 'dismissStaleReviews'; installationId: number; repository: string; pullRequestNumber: number; approvingReviewId: string; approvingAuthor: string; } export type FactoryCommitDecision = FactoryTransitionDecision | FactoryDismissStaleReviewsDecision | FactoryUpsertLinkedWorkItemDecision | FactoryInvokeSkillDecision | FactorySendMessageDecision | FactoryNotifyDecision; export type FactoryRuleDecision = FactoryRuleRejectDecision | FactoryCommitDecision; export interface FactoryTransitionResultAccepted { status: 'accepted'; transitionId: string; itemId: string; revision: number; stage: FactoryRuleStage; decisions: FactoryCommitDecision[]; } export interface FactoryTransitionResultRejected { status: 'rejected'; transitionId: string; itemId: string; code: FactoryRuleRejectionCode; reason: string; } export type FactoryTransitionResult = FactoryTransitionResultAccepted | FactoryTransitionResultRejected; export declare function factoryRuleSourceForWorkItem(source: WorkItemSource): FactoryRuleSource; export {}; //# sourceMappingURL=types.d.ts.map