import type { Task, TaskStore } from "../../types.js"; import type { IntegrationId, SyncResult } from "../sync/index.js"; /** * Progress callback for sync operations. */ export interface SyncProgress { /** Current task index (1-based) */ current: number; /** Total number of tasks */ total: number; /** Task being processed */ task: Task; /** Current phase of the sync */ phase: "checking" | "creating" | "updating" | "skipped"; } /** * Cached story data for efficient sync operations. */ export interface CachedStory { id: number; name: string; description: string; completed: boolean; labels: string[]; /** Workflow state ID - used to prevent moving done stories backwards */ workflow_state_id: number; } export interface ShortcutSyncServiceOptions { /** Shortcut API token */ token: string; /** Shortcut workspace slug */ workspace: string; /** Team ID or mention name for story creation */ team: string; /** Workflow ID to use (uses team default if not set) */ workflow?: number; /** Label name for dex stories (default: "dex") */ label?: string; } export interface SyncAllOptions { /** Callback for progress updates */ onProgress?: (progress: SyncProgress) => void; /** Whether to skip unchanged tasks (default: true) */ skipUnchanged?: boolean; } /** * Shortcut Sync Service * * Provides one-way sync of tasks to Shortcut Stories. * File storage remains the source of truth. * * Behavior: * - Top-level tasks (no parent_id) -> Create/update Shortcut Story * - Subtasks -> Create as Shortcut Sub-tasks linked to parent story * - Blockers -> Synced as "blocks" story links * - Completed tasks -> Story moved to "done" workflow state * - Pending tasks -> Story in "unstarted" or "started" state */ export declare class ShortcutSyncService { readonly id: IntegrationId; readonly displayName = "Shortcut"; private api; private workspace; private teamId; private workflowId; private label; private workflowCache; private resolvedTeamId; private resolvedWorkflowId; constructor(options: ShortcutSyncServiceOptions); /** * Get the workspace this service syncs to. */ getWorkspace(): string; /** * Get the Shortcut story ID from a task. * Returns null if task hasn't been synced yet. */ getRemoteId(task: Task): number | null; /** * Get the Shortcut story URL from a task. * Returns null if task hasn't been synced yet. */ getRemoteUrl(task: Task): string | null; /** * Close the Shortcut story for a task (e.g., when the task is deleted locally). * Moves the story to the "done" workflow state. * If the task has no associated story, this is a no-op. */ closeRemote(task: Task): Promise; /** * Resolve the team ID (handles mention names). */ private resolveTeamId; /** * Get or fetch workflow. */ private getWorkflow; /** * Get the workflow ID to use for new stories. */ private getWorkflowId; /** * Get the appropriate workflow state ID for a task. * * @param task - The task to get state for * @param workflowId - The workflow ID * @param shouldBeCompleted - Optional override for completion status. If not provided, * falls back to task.completed (for backward compatibility). */ private getWorkflowStateId; /** * Get the workflow state type from a state ID. */ private getWorkflowStateType; /** * Sync a single task to Shortcut. * For subtasks, syncs the parent story instead. * Returns sync result with shortcut metadata. */ syncTask(task: Task, store: TaskStore): Promise; /** * Sync all tasks to Shortcut. * Returns array of sync results. */ syncAll(store: TaskStore, options?: SyncAllOptions): Promise; /** * Build a SyncResult for an existing story. */ private buildSyncResult; /** * Sync a parent task (with all descendants) to Shortcut. * Returns sync result with shortcut metadata. */ private syncParentTask; /** * Sync subtasks as Shortcut Sub-tasks. * Returns sync results for all subtasks (including nested) so metadata can be saved. */ private syncSubtasks; /** * Sync blocker relationships as Shortcut story links. * Creates "blocks" links for tasks that this task is blocked by. */ private syncBlockers; /** * Check if a story has changed using cached data. */ private hasStoryChangedFromCache; /** * Check if a story has changed and get its current workflow state. * Returns both change detection result and current state for safe updates. * When we can't fetch the story, currentWorkflowStateId is undefined to preserve remote state. */ private getStoryChangeResult; /** * Fetch only the workflow state ID of a story (for when we need to avoid moving backwards). * Returns undefined if the story can't be fetched. */ private fetchStoryWorkflowStateId; /** * Compare story data against expected values. * Returns true if any field differs (story needs updating). */ private storyNeedsUpdate; /** * Create a new Shortcut story for a task. * Returns the shortcut metadata for the created story. */ private createStory; /** * Update an existing Shortcut story. * * @param currentWorkflowStateId - The current workflow state ID of the story. * undefined means we don't know the current state. * Used to prevent moving done stories backwards. */ private updateStory; /** * Determine if a task should be marked as completed in Shortcut. * * - If task has a commit SHA: only mark completed if that commit is pushed to origin * - If task has no commit SHA: don't mark completed (can't verify work is merged) * * This ensures Shortcut stories are only moved to "done" when the actual work has been pushed. * Tasks completed with --no-commit will remain in "started" state until manually moved. */ private shouldMarkCompleted; /** * Look up a task by its local ID in Shortcut stories. * Uses search to find stories with the dex task ID in the description. */ findStoryByTaskId(taskId: string): Promise; /** * Fetch all dex-labeled stories. * Returns a Map keyed by task ID containing all data needed for change detection. */ fetchAllDexStories(): Promise>; } /** * Extract Shortcut story ID from task metadata. * Returns null if not synced yet. */ export declare function getShortcutStoryId(task: Task): number | null; //# sourceMappingURL=sync.d.ts.map