trellis
Version:
Agentic State Engine — event-sourced causal graph with branching, decision traces, and realtime sync for AI-native applications
227 lines • 7.89 kB
TypeScript
/**
* Issue Module
*
* Extracted per DESIGN.md pattern (like milestone.ts, branch.ts).
* Handles issue creation, lifecycle (start/pause/resume/close/reopen),
* acceptance criteria, and queries.
*/
import type { VcsOp, IssueType } from './types.js';
import type { EngineContext } from './engine-context.js';
import { type CriterionTemplate } from './test-manifest.js';
export interface IssueInfo {
/**
* Canonical, collision-resistant identifier.
* Legacy unlaned issues use `TRL-N`; lane-scoped use `issue:<laneId>:<seq>`.
* Always present; safe to use as a map key, link target, and nack ref.
*/
id: string;
/**
* Optional human-readable name.
* For legacy `TRL-N` ids this mirrors `id`. For lane-scoped ids it is
* undefined until a promotion step assigns one. UI may fall back to `id`.
*/
displayId?: string;
title?: string;
description?: string;
/**
* What kind of issue this is (ADR 0026) — `epic` containers hold intent and
* leaves roll up to them via `parentId`. Absent on ops minted before the field
* existed; treat as `issue`.
*/
issueType?: string;
status?: string;
priority?: string;
labels: string[];
assignee?: string;
createdAt?: string;
createdBy?: string;
startedAt?: string;
pausedAt?: string;
pauseNote?: string;
closedAt?: string;
parentId?: string;
branchName?: string;
claimedLaneId?: string;
claimedSessionId?: string;
claimedAt?: string;
blockedBy: string[];
blocking: string[];
isBlocked: boolean;
criteria: CriterionInfo[];
}
export interface CriterionInfo {
id: string;
description?: string;
command?: string;
suite?: string;
status?: string;
lastRunAt?: string;
lastOutput?: string;
/** Retracted via `vcs:criterionRemove`. Hidden from projections; the entity survives so its id is never reused. */
retracted?: boolean;
}
export interface CriterionResult {
id: string;
description?: string;
command?: string;
status: 'passed' | 'failed' | 'skipped';
output?: string;
exitCode?: number;
}
export interface IssueFilters {
status?: string;
assignee?: string;
label?: string;
parentId?: string;
blocked?: boolean;
/** ADR 0026 — `--type epic` is the query a title prefix could never support. */
issueType?: string;
}
export interface IssueCreateOptions {
/** What kind of issue (ADR 0026). Default `issue`; `epic` holds intent. */
issueType?: IssueType;
priority?: 'critical' | 'high' | 'medium' | 'low';
labels?: string[];
assignee?: string;
parentId?: string;
description?: string;
status?: 'backlog' | 'queue';
criteria?: Array<{
description: string;
command?: string;
suite?: string;
}>;
/**
* Creates a collision-resistant canonical ID scoped to this lane, e.g.
* `issue:lane-a:1`. Omit to keep the legacy repo-wide `TRL-N` allocator.
*/
laneId?: string;
/**
* Recovery-only: mint a specific legacy `TRL-N` id. Bumps the repo counter so
* later allocates continue above N. Refuses if the id already exists.
*/
forceIssueId?: string;
}
/**
* Create a new issue.
*/
export declare function createIssue(ctx: EngineContext, rootPath: string, title: string, opts?: IssueCreateOptions): Promise<VcsOp>;
/**
* Update an issue's metadata.
*/
export declare function updateIssue(ctx: EngineContext, id: string, updates: {
title?: string;
description?: string;
/** Re-kind an issue (ADR 0026) — e.g. promoting a task to an epic. */
issueType?: IssueType;
priority?: 'critical' | 'high' | 'medium' | 'low';
labels?: string[];
assignee?: string;
status?: 'backlog' | 'queue' | 'in_progress' | 'paused' | 'closed';
/** Set parent issue id, or `null` to remove an existing parent link. */
parentId?: string | null;
}): Promise<VcsOp>;
/**
* Start working on an issue: sets in_progress, auto-assigns, creates branch.
* Returns the issueStart op. The caller (engine) is responsible for
* actually creating the branch and switching to it.
*/
export declare function startIssue(ctx: EngineContext, id: string,
/** Omitted when starting without a branch — the lane is the isolation. */
branchName?: string): Promise<VcsOp>;
/**
* Auto-attach acceptance criteria from `.trellis/tests.json` on issue start.
* Skips when the issue already has criteria.
*/
export declare function applyIssueStartCriteria(ctx: EngineContext, issueId: string, rootPath: string, labels?: string[]): Promise<CriterionTemplate[]>;
/**
* Pause an in-progress issue.
*/
export declare function pauseIssue(ctx: EngineContext, id: string, note: string): Promise<VcsOp>;
/**
* Resume a paused issue.
*/
export declare function resumeIssue(ctx: EngineContext, id: string): Promise<VcsOp>;
/**
* Close an issue. Requires all criteria to have passed and confirm=true.
*/
export declare function closeIssue(ctx: EngineContext, id: string, opts?: {
confirm?: boolean;
}): Promise<{
op?: VcsOp;
criteriaResults: CriterionResult[];
}>;
/**
* Triage a backlog issue to queue (ready to start).
*/
export declare function triageIssue(ctx: EngineContext, id: string): Promise<VcsOp>;
/**
* Reopen a closed issue.
*/
export declare function reopenIssue(ctx: EngineContext, id: string): Promise<VcsOp>;
/**
* Assign an issue to an agent.
*/
export declare function assignIssue(ctx: EngineContext, id: string, agentId: string): Promise<VcsOp>;
/**
* Block an issue by another issue.
*/
export declare function blockIssue(ctx: EngineContext, id: string, blockedById: string): Promise<VcsOp>;
/**
* Remove a blocking relationship.
*/
export declare function unblockIssue(ctx: EngineContext, id: string, blockedById: string): Promise<VcsOp>;
/**
* Add an acceptance criterion to an issue.
*/
export declare function addCriterion(ctx: EngineContext, issueId: string, description: string, opts?: {
command?: string;
suite?: string;
}): Promise<VcsOp>;
/**
* Manually set a criterion's status (for non-command criteria).
*/
export declare function setCriterionStatus(ctx: EngineContext, issueId: string, criterionIndex: number, status: 'passed' | 'failed' | 'pending'): Promise<VcsOp>;
/**
* Retract an acceptance criterion (TRL-1).
*
* `criterionIndex` is 1-based over the *live* criteria, matching what
* `issue show` prints and what `ac-pass` / `ac-fail` accept.
*
* The criterion entity is not deleted — `vcs:criterionRemove` marks it
* retracted, so no existing op is rewritten (TRL-1 AC#1) and the id is
* retired rather than freed for reuse.
*/
export declare function removeCriterion(ctx: EngineContext, issueId: string, criterionIndex: number): Promise<VcsOp>;
/**
* Run all acceptance criteria for an issue. Executes test commands
* and emits criterionUpdate + vcs:testRun ops with results.
*/
export declare function runCriteria(ctx: EngineContext, issueId: string, cwd: string, opts?: {
laneId?: string;
manifestRoot?: string;
}): Promise<CriterionResult[]>;
/**
* List all issues, optionally filtered.
*/
export declare function listIssues(ctx: EngineContext, filters?: IssueFilters): IssueInfo[];
/**
* Get a single issue by ID.
*/
export declare function getIssue(ctx: EngineContext, id: string): IssueInfo | null;
/**
* Get all active (in_progress) issues.
*/
export declare function getActiveIssues(ctx: EngineContext): IssueInfo[];
export interface CompletionReadiness {
ready: boolean;
queue: IssueInfo[];
paused: IssueInfo[];
inProgress: IssueInfo[];
summary: string;
}
/**
* Check whether all work is complete: no issues in queue, paused, or in_progress.
*/
export declare function checkCompletionReadiness(ctx: EngineContext): CompletionReadiness;
//# sourceMappingURL=issue.d.ts.map