{
  "version": 3,
  "sources": ["../src/index.ts", "../src/ai/completion.ts", "../src/ai/policies.ts", "../src/ai/textLimits.ts", "../src/gitlab/encoding.ts", "../src/gitlab/audit.ts", "../src/gitlab/errors.ts", "../src/gitlab/query.ts", "../src/gitlab/client.ts", "../src/gitlab/deployments.ts", "../src/gitlab/epics.ts", "../src/gitlab/events.ts", "../src/gitlab/issues.ts", "../src/gitlab/mergeRequests.ts", "../src/gitlab/pipelines.ts", "../src/gitlab/repository.ts", "../src/gitlab/projectMeta.ts", "../src/gitlab/releases.ts", "../src/gitlab/search.ts", "../src/gitlab/security.ts", "../src/gitlab/wikiAndSnippets.ts", "../src/insights/activity.ts", "../src/insights/deployments.ts", "../src/insights/epics.ts", "../src/insights/issues.ts", "../src/insights/mergeRequests.ts", "../src/insights/pipelines.ts", "../src/insights/projectDoc.ts", "../src/insights/releases.ts", "../src/insights/repository.ts", "../src/insights/searchBundle.ts", "../src/insights/security.ts", "../src/insights/wiki.ts", "../src/integrations/smartDiffBridge.ts"],
  "sourcesContent": ["/**\n * GitLab REST helpers + LLM insights powered by `@mcarvin/smart-diff`'s\n * built-in chat client. Smart diffing uses `@mcarvin/smart-diff` (any git\n * repo or GitLab-supplied patches), and the LLM layer supports OpenAI,\n * Anthropic, Google, Bedrock, Mistral, Cohere, Groq, xAI, DeepSeek, or any\n * OpenAI-compatible gateway.\n */\n\nexport type {\n  ChatCallOptions,\n  ChatModel,\n  ChatResult,\n  ChatUsage,\n  CommitInfo,\n  DiffFileSummary,\n  DiffPathFilter,\n  DiffShapingOptions,\n  DiffSummary,\n  GenerateSummaryInput,\n  GitDiffAiSummaryOptions,\n  GitDiffRangeQuery,\n  LlmModelProvider,\n  ResolveLanguageModelOptions,\n  SummarizeFlags,\n} from \"@mcarvin/smart-diff\";\n/** Re-export smart-diff for local git repos and advanced use. */\nexport {\n  createGitClient,\n  DEFAULT_GIT_DIFF_SYSTEM_PROMPT,\n  DEFAULT_NOISE_EXCLUDES,\n  defaultModelForProvider,\n  detectLlmProvider,\n  filterCommitsByMessageRegexes,\n  generateSummary,\n  getChangedFiles,\n  getCommits,\n  getDiff,\n  getDiffSummary,\n  getRepoRoot,\n  isLlmProviderConfigured,\n  LLM_GATEWAY_REQUIRED_MESSAGE,\n  parseLlmDefaultHeadersFromEnv,\n  resolveLanguageModel,\n  resolveLlmBaseUrl,\n  resolveLlmMaxDiffChars,\n  shapeUnifiedDiff,\n  summarizeGitDiff,\n  truncateUnifiedDiffForLlm,\n} from \"@mcarvin/smart-diff\";\nexport {\n  type CreateLabflowLlmOptions,\n  createLabflowLlm,\n} from \"./ai/completion.js\";\nexport {\n  POLICY_DEFAULT,\n  POLICY_HUMAN_REVIEW,\n  POLICY_NO_SECRET_EXFILTRATION,\n  POLICY_SECURITY_FINDINGS,\n} from \"./ai/policies.js\";\nexport { truncateForPrompt } from \"./ai/textLimits.js\";\nexport type {\n  LabflowLanguageModelProvider,\n  LabflowLlm,\n  LlmProviderId,\n} from \"./ai/types.js\";\nexport { listProjectAuditEvents } from \"./gitlab/audit.js\";\nexport { GitlabClient, type GitlabClientOptions } from \"./gitlab/client.js\";\nexport { listDeployments, listEnvironments } from \"./gitlab/deployments.js\";\nexport { encodeGroupId, encodeProjectId } from \"./gitlab/encoding.js\";\nexport { getEpic, listEpicIssues, listGroupEpics } from \"./gitlab/epics.js\";\nexport { GitlabHttpError } from \"./gitlab/errors.js\";\nexport { listGroupEvents, listProjectEvents } from \"./gitlab/events.js\";\nexport {\n  createIssueNote,\n  getIssue,\n  listIssueNotes,\n  listProjectIssues,\n} from \"./gitlab/issues.js\";\nexport {\n  createMergeRequestNote,\n  getMergeRequest,\n  getMergeRequestChanges,\n  listMergeRequestCommits,\n  listMergeRequestDiscussions,\n  listMergeRequestNotes,\n} from \"./gitlab/mergeRequests.js\";\nexport {\n  getJob,\n  getJobTrace,\n  getPipeline,\n  listPipelineJobs,\n  listPipelines,\n} from \"./gitlab/pipelines.js\";\nexport { getProject, getReadmeFile } from \"./gitlab/projectMeta.js\";\nexport { encodeQuery } from \"./gitlab/query.js\";\nexport {\n  getReleaseByTag,\n  listReleases,\n  type UpsertReleaseParams,\n  upsertRelease,\n} from \"./gitlab/releases.js\";\nexport {\n  compareRefs,\n  createCommitNote,\n  getFile,\n  listCommitComments,\n  listCommits,\n} from \"./gitlab/repository.js\";\nexport {\n  type SearchScope,\n  searchGitlab,\n  searchInGroup,\n  searchInProject,\n} from \"./gitlab/search.js\";\nexport { listVulnerabilityFindings } from \"./gitlab/security.js\";\nexport type {\n  AuditEvent,\n  Blob,\n  Commit,\n  Deployment,\n  Environment,\n  Epic,\n  Event,\n  Issue,\n  MergeRequest,\n  MergeRequestChange,\n  Note,\n  Pipeline,\n  PipelineJob,\n  Project,\n  Release,\n  RepositoryCompare,\n  Snippet,\n  VulnerabilityFinding,\n  WikiPage,\n} from \"./gitlab/types.js\";\nexport {\n  type CreateWikiPageParams,\n  createWikiPage,\n  getSnippet,\n  getWikiPage,\n  listProjectSnippets,\n  listWikiPages,\n  type UpdateWikiPageParams,\n  type UpsertWikiPageParams,\n  updateWikiPage,\n  upsertWikiPage,\n} from \"./gitlab/wikiAndSnippets.js\";\nexport {\n  aiGroupWeeklyDigest,\n  aiProjectWeeklyDigest,\n} from \"./insights/activity.js\";\nexport { aiPostDeployIncidentBrief } from \"./insights/deployments.js\";\nexport { aiEpicRoadmapRollup } from \"./insights/epics.js\";\nexport {\n  type AiIssueInsightOptions,\n  aiIssueSuggestedNextStep,\n  aiIssueThreadSummary,\n  aiStaleIssueSummary,\n  listOpenIssuesForProject,\n} from \"./insights/issues.js\";\nexport {\n  type AiMergeRequestInsightOptions,\n  aiMergeRequestActionItems,\n  aiMergeRequestDiscussionDigest,\n  aiMergeRequestReviewerBriefingMeta,\n  aiSuggestedMergeRequestReply,\n  aiWhatChangedSinceLastReview,\n  type ReviewSinceOptions,\n} from \"./insights/mergeRequests.js\";\nexport {\n  type AiPipelineInsightOptions,\n  aiPipelineJobLogSummary,\n  aiPipelineRunSummary,\n} from \"./insights/pipelines.js\";\nexport { aiProjectReadmeConsistency } from \"./insights/projectDoc.js\";\nexport {\n  type AiDraftReleaseNotesOptions,\n  type AiListReleasesOverviewOptions,\n  aiDraftReleaseNotes,\n  aiListReleasesOverview,\n} from \"./insights/releases.js\";\nexport {\n  type AiCommitCommentsDigestOptions,\n  aiCommitCommentsDigest,\n  aiCommitsReleaseNoteBullets,\n  aiCompareRefsNarrative,\n  aiConventionalCommitNudge,\n  aiExplainRepositoryPath,\n  type ExplainPathOptions,\n} from \"./insights/repository.js\";\nexport { aiSearchMentionBundle } from \"./insights/searchBundle.js\";\nexport {\n  aiAuditEventsDashboardSummary,\n  aiVulnerabilityFindingsBrief,\n} from \"./insights/security.js\";\nexport {\n  type AiWikiInsightOptions,\n  type AiWikiOutdatedDocHintsOptions,\n  type AiWikiRunbookTldrOptions,\n  aiSnippetTldr,\n  aiSuggestMergeWikiPages,\n  aiWikiOutdatedDocHints,\n  aiWikiRunbookTldr,\n} from \"./insights/wiki.js\";\nexport {\n  type SummarizeCompareDiffOptions,\n  type SummarizeGitLabMergeRequestDiffOptions,\n  summarizeCompareDiffWithSmartDiff,\n  summarizeMergeRequestDiffWithSmartDiff,\n} from \"./integrations/smartDiffBridge.js\";\n", "import {\n  type ChatModel,\n  isLlmProviderConfigured,\n  LLM_GATEWAY_REQUIRED_MESSAGE,\n  type LlmProviderId,\n  resolveLanguageModel,\n} from \"@mcarvin/smart-diff\";\nimport { POLICY_DEFAULT } from \"./policies.js\";\nimport { truncateForPrompt } from \"./textLimits.js\";\nimport type { LabflowLanguageModelProvider, LabflowLlm } from \"./types.js\";\n\nexport type CreateLabflowLlmOptions = {\n  /**\n   * Explicit provider id. When omitted, smart-diff's env-based auto-detection\n   * picks one (see `LLM_PROVIDER` / README for the resolution order).\n   */\n  provider?: LlmProviderId;\n  /** Overrides `LLM_MODEL` env and the per-provider default model. */\n  defaultModel?: string;\n  /** Bound total user prompt size after truncation. */\n  maxUserChars?: number;\n  /**\n   * Bypass env-based provider resolution entirely \u2014 hand-wire a smart-diff\n   * `ChatModel` (e.g. to attach middlewares, retries, or a test mock).\n   * When set, `provider` / `defaultModel` are ignored.\n   */\n  languageModelProvider?: LabflowLanguageModelProvider;\n};\n\n/**\n * Build a {@link LabflowLlm} backed by `@mcarvin/smart-diff`'s chat client.\n * Any provider supported by smart-diff works: `openai`, `openai-compatible`,\n * `anthropic`, `google`, `bedrock`, `mistral`, `cohere`, `groq`, `xai`,\n * `deepseek`.\n *\n * Configuration is the same as `@mcarvin/smart-diff` (see its README):\n * - `LLM_PROVIDER` explicitly selects a provider; otherwise auto-detected\n *   from env vars (`LLM_BASE_URL`/`OPENAI_BASE_URL` \u2192 `openai-compatible`,\n *   `OPENAI_API_KEY`/`LLM_API_KEY` \u2192 `openai`, `ANTHROPIC_API_KEY`,\n *   `GOOGLE_GENERATIVE_AI_API_KEY`, `MISTRAL_API_KEY`, `COHERE_API_KEY`,\n *   `GROQ_API_KEY`, `XAI_API_KEY`, `DEEPSEEK_API_KEY`, and finally\n *   header-only auth via `OPENAI_DEFAULT_HEADERS`/`LLM_DEFAULT_HEADERS`).\n * - `LLM_MODEL` overrides the per-provider default model id.\n * - `OPENAI_DEFAULT_HEADERS` / `LLM_DEFAULT_HEADERS` carry extra headers for\n *   OpenAI / OpenAI-compatible requests (e.g. RBAC tokens).\n */\nexport function createLabflowLlm(\n  options: CreateLabflowLlmOptions = {},\n): LabflowLlm {\n  const maxUserChars = options.maxUserChars ?? 120_000;\n  const envModel = process.env.LLM_MODEL ?? process.env.OPENAI_MODEL;\n  const defaultModel = options.defaultModel ?? envModel;\n\n  const resolveModel = async (modelId?: string): Promise<ChatModel> => {\n    if (options.languageModelProvider) {\n      return options.languageModelProvider();\n    }\n    if (!isLlmProviderConfigured()) {\n      throw new Error(LLM_GATEWAY_REQUIRED_MESSAGE);\n    }\n    return resolveLanguageModel({\n      provider: options.provider,\n      model: modelId ?? defaultModel,\n    });\n  };\n\n  return async (input) => {\n    const user = truncateForPrompt(input.user, maxUserChars);\n    const system = [POLICY_DEFAULT, input.system].filter(Boolean).join(\"\\n\\n\");\n    const model = await resolveModel(input.model);\n\n    const { text } = await model.generate({\n      system,\n      prompt: user,\n      temperature: resolveTemperature(),\n      maxOutputTokens: resolveMaxOutputTokens(),\n    });\n\n    if (!text) {\n      throw new Error(\"LLM response had no text content.\");\n    }\n    return text;\n  };\n}\n\n/** Same env var and default (0.2) as `@mcarvin/smart-diff`'s internal resolver. */\nfunction resolveTemperature(): number {\n  const raw = process.env.LLM_TEMPERATURE?.trim();\n  if (raw) {\n    const parsed = Number.parseFloat(raw);\n    if (Number.isFinite(parsed)) {\n      return Math.min(2, Math.max(0, parsed));\n    }\n  }\n  return 0.2;\n}\n\n/** Same env vars and default (4000) as `@mcarvin/smart-diff`'s internal resolver. */\nfunction resolveMaxOutputTokens(): number {\n  const raw = process.env.LLM_MAX_TOKENS ?? process.env.OPENAI_MAX_TOKENS;\n  const parsed = raw !== undefined ? Number.parseInt(raw, 10) : 4000;\n  return Number.isFinite(parsed) && parsed > 0 ? parsed : 4000;\n}\n", "/** Embed in system prompts; tune for your org. */\nexport const POLICY_NO_SECRET_EXFILTRATION =\n  \"Never repeat or infer secrets (tokens, keys, passwords, private URLs). If content looks like a credential, refuse to reproduce it.\";\n\nexport const POLICY_SECURITY_FINDINGS =\n  \"Security findings are advisory only. Never recommend auto-merging fixes blindly; humans must verify impact, rollout, and policy.\";\n\nexport const POLICY_HUMAN_REVIEW =\n  \"You assist human reviewers and maintainers. Do not claim to have shipped, merged, or approved changes.\";\n\nexport const POLICY_DEFAULT = [\n  POLICY_NO_SECRET_EXFILTRATION,\n  POLICY_HUMAN_REVIEW,\n].join(\"\\n\");\n", "const DEFAULT_MAX = 120_000;\n\n/** Trim long text for prompts (characters, not bytes). */\nexport function truncateForPrompt(\n  text: string,\n  maxChars: number = DEFAULT_MAX,\n): string {\n  if (text.length <= maxChars) {\n    return text;\n  }\n  return `${text.slice(0, maxChars)}\\n\\n[Truncated: ${text.length} chars \u2192 ${maxChars}]`;\n}\n", "/** Encode a project id or path for use in `/projects/:id/...` URLs. */\nexport function encodeProjectId(projectId: string | number): string {\n  return encodeURIComponent(String(projectId));\n}\n\n/** Encode a group id or path for `/groups/:id/...` URLs. */\nexport function encodeGroupId(groupId: string | number): string {\n  return encodeURIComponent(String(groupId));\n}\n", "import type { GitlabClient } from \"./client.js\";\nimport { encodeProjectId } from \"./encoding.js\";\nimport type { AuditEvent } from \"./types.js\";\n\nexport async function listProjectAuditEvents(\n  client: GitlabClient,\n  projectId: string | number,\n  query?: Record<string, string | number | boolean | undefined>,\n): Promise<AuditEvent[]> {\n  const id = encodeProjectId(projectId);\n  return client.requestAllPages<AuditEvent>(\n    `/projects/${id}/audit_events`,\n    query ?? {},\n  );\n}\n", "export class GitlabHttpError extends Error {\n  readonly status: number;\n  readonly body: string;\n\n  constructor(message: string, init: { status: number; body: string }) {\n    super(message);\n    this.name = \"GitlabHttpError\";\n    this.status = init.status;\n    this.body = init.body;\n  }\n}\n", "export function encodeQuery(\n  params: Record<string, string | number | boolean | undefined>,\n): string {\n  const pairs: string[] = [];\n  for (const [k, v] of Object.entries(params)) {\n    if (v === undefined) {\n      continue;\n    }\n    pairs.push(`${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`);\n  }\n  return pairs.length ? `?${pairs.join(\"&\")}` : \"\";\n}\n", "import { GitlabHttpError } from \"./errors.js\";\nimport { encodeQuery } from \"./query.js\";\n\nexport type GitlabClientOptions = {\n  /** Base URL including `/api/v4`, e.g. `https://gitlab.com/api/v4`. */\n  baseUrl?: string;\n  /** Private token (`PRIVATE-TOKEN` header) or OAuth bearer (`Authorization: Bearer`). */\n  token: string;\n  /** When true, use `Authorization: Bearer` instead of `PRIVATE-TOKEN`. */\n  oauth?: boolean;\n  /** Custom fetch (tests, proxies). Defaults to global fetch. */\n  fetchFn?: typeof fetch;\n};\n\nfunction normalizeBaseUrl(raw: string): string {\n  const trimmed = raw.replace(/\\/+$/, \"\");\n  return trimmed.endsWith(\"/api/v4\") ? trimmed : `${trimmed}/api/v4`;\n}\n\nexport class GitlabClient {\n  readonly baseUrl: string;\n  readonly token: string;\n  readonly oauth: boolean;\n  private readonly fetchImpl: typeof fetch;\n\n  constructor(options: GitlabClientOptions) {\n    this.baseUrl = normalizeBaseUrl(\n      options.baseUrl ?? \"https://gitlab.com/api/v4\",\n    );\n    this.token = options.token;\n    this.oauth = options.oauth ?? false;\n    this.fetchImpl = options.fetchFn ?? fetch;\n  }\n\n  private headers(): HeadersInit {\n    return this.oauth\n      ? {\n          Authorization: `Bearer ${this.token}`,\n          \"Content-Type\": \"application/json\",\n        }\n      : { \"PRIVATE-TOKEN\": this.token, \"Content-Type\": \"application/json\" };\n  }\n\n  async request<T>(\n    method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\",\n    path: string,\n    init?: {\n      query?: Record<string, string | number | boolean | undefined>;\n      body?: unknown;\n    },\n  ): Promise<T> {\n    const q = init?.query ? encodeQuery(init.query) : \"\";\n    const url = `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}${q}`;\n\n    const res = await this.fetchImpl(url, {\n      method,\n      headers: this.headers(),\n      body: init?.body !== undefined ? JSON.stringify(init.body) : undefined,\n    });\n\n    const text = await res.text();\n    if (!res.ok) {\n      throw new GitlabHttpError(\n        `GitLab ${method} ${path} failed: ${res.status}`,\n        {\n          status: res.status,\n          body: text,\n        },\n      );\n    }\n\n    if (!text || text.trim().length === 0) {\n      return undefined as T;\n    }\n\n    try {\n      return JSON.parse(text) as T;\n    } catch {\n      throw new GitlabHttpError(\n        `GitLab ${method} ${path}: response was not JSON`,\n        {\n          status: res.status,\n          body: text.slice(0, 2000),\n        },\n      );\n    }\n  }\n\n  /**\n   * Like {@link request} but returns the response body as plain text (no JSON parse).\n   * Used for endpoints such as `GET /projects/:id/jobs/:job_id/trace`.\n   */\n  async requestText(\n    method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\",\n    path: string,\n    init?: {\n      query?: Record<string, string | number | boolean | undefined>;\n      body?: unknown;\n    },\n  ): Promise<string> {\n    const q = init?.query ? encodeQuery(init.query) : \"\";\n    const url = `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}${q}`;\n\n    const res = await this.fetchImpl(url, {\n      method,\n      headers: this.headers(),\n      body: init?.body !== undefined ? JSON.stringify(init.body) : undefined,\n    });\n\n    const text = await res.text();\n    if (!res.ok) {\n      throw new GitlabHttpError(\n        `GitLab ${method} ${path} failed: ${res.status}`,\n        {\n          status: res.status,\n          body: text,\n        },\n      );\n    }\n\n    return text;\n  }\n\n  /** Page through GitLab list endpoints until a short page or empty result. */\n  async requestAllPages<T>(\n    path: string,\n    query: Record<string, string | number | boolean | undefined> = {},\n    maxPages = 100,\n  ): Promise<T[]> {\n    const perPage = Number(query.per_page ?? 100);\n    const out: T[] = [];\n    for (let page = 1; page <= maxPages; page++) {\n      const chunk = await this.request<T[]>(\"GET\", path, {\n        query: { ...query, page, per_page: perPage },\n      });\n      if (!Array.isArray(chunk) || chunk.length === 0) {\n        break;\n      }\n      out.push(...chunk);\n      if (chunk.length < perPage) {\n        break;\n      }\n    }\n    return out;\n  }\n}\n", "import type { GitlabClient } from \"./client.js\";\nimport { encodeProjectId } from \"./encoding.js\";\nimport type { Deployment, Environment } from \"./types.js\";\n\nexport async function listDeployments(\n  client: GitlabClient,\n  projectId: string | number,\n  query?: Record<string, string | number | boolean | undefined>,\n): Promise<Deployment[]> {\n  const id = encodeProjectId(projectId);\n  return client.requestAllPages<Deployment>(\n    `/projects/${id}/deployments`,\n    query ?? {},\n  );\n}\n\nexport async function listEnvironments(\n  client: GitlabClient,\n  projectId: string | number,\n): Promise<Environment[]> {\n  const id = encodeProjectId(projectId);\n  return client.requestAllPages<Environment>(`/projects/${id}/environments`);\n}\n", "import type { GitlabClient } from \"./client.js\";\nimport { encodeGroupId } from \"./encoding.js\";\nimport type { Epic } from \"./types.js\";\n\nexport async function getEpic(\n  client: GitlabClient,\n  groupId: string | number,\n  epicIid: number,\n): Promise<Epic> {\n  const gid = encodeGroupId(groupId);\n  return client.request<Epic>(\"GET\", `/groups/${gid}/epics/${epicIid}`);\n}\n\nexport async function listEpicIssues(\n  client: GitlabClient,\n  groupId: string | number,\n  epicIid: number,\n): Promise<\n  Array<{\n    id: number;\n    iid: number;\n    title: string;\n    state?: string;\n    web_url?: string;\n  }>\n> {\n  const gid = encodeGroupId(groupId);\n  return client.requestAllPages(`/groups/${gid}/epics/${epicIid}/issues`);\n}\n\nexport async function listGroupEpics(\n  client: GitlabClient,\n  groupId: string | number,\n  query?: Record<string, string | number | boolean | undefined>,\n): Promise<Epic[]> {\n  const gid = encodeGroupId(groupId);\n  return client.requestAllPages<Epic>(`/groups/${gid}/epics`, query ?? {});\n}\n", "import type { GitlabClient } from \"./client.js\";\nimport { encodeGroupId, encodeProjectId } from \"./encoding.js\";\nimport type { Event } from \"./types.js\";\n\nexport async function listProjectEvents(\n  client: GitlabClient,\n  projectId: string | number,\n  query?: Record<string, string | number | boolean | undefined>,\n): Promise<Event[]> {\n  const id = encodeProjectId(projectId);\n  return client.requestAllPages<Event>(`/projects/${id}/events`, query ?? {});\n}\n\nexport async function listGroupEvents(\n  client: GitlabClient,\n  groupId: string | number,\n  query?: Record<string, string | number | boolean | undefined>,\n): Promise<Event[]> {\n  const gid = encodeGroupId(groupId);\n  return client.requestAllPages<Event>(`/groups/${gid}/events`, query ?? {});\n}\n", "import type { GitlabClient } from \"./client.js\";\nimport { encodeProjectId } from \"./encoding.js\";\nimport type { Issue, Note } from \"./types.js\";\n\nexport async function getIssue(\n  client: GitlabClient,\n  projectId: string | number,\n  issueIid: number,\n): Promise<Issue> {\n  const id = encodeProjectId(projectId);\n  return client.request<Issue>(\"GET\", `/projects/${id}/issues/${issueIid}`);\n}\n\nexport async function listIssueNotes(\n  client: GitlabClient,\n  projectId: string | number,\n  issueIid: number,\n): Promise<Note[]> {\n  const id = encodeProjectId(projectId);\n  return client.requestAllPages<Note>(\n    `/projects/${id}/issues/${issueIid}/notes`,\n  );\n}\n\n/** Create a note on the issue. Requires API token with write access. */\nexport async function createIssueNote(\n  client: GitlabClient,\n  projectId: string | number,\n  issueIid: number,\n  params: { body: string },\n): Promise<Note> {\n  const id = encodeProjectId(projectId);\n  return client.request<Note>(\n    \"POST\",\n    `/projects/${id}/issues/${issueIid}/notes`,\n    {\n      body: params,\n    },\n  );\n}\n\nexport async function listProjectIssues(\n  client: GitlabClient,\n  projectId: string | number,\n  query?: Record<string, string | number | boolean | undefined>,\n): Promise<Issue[]> {\n  const id = encodeProjectId(projectId);\n  return client.requestAllPages<Issue>(`/projects/${id}/issues`, query ?? {});\n}\n", "import type { GitlabClient } from \"./client.js\";\nimport { encodeProjectId } from \"./encoding.js\";\nimport type {\n  Commit,\n  MergeRequest,\n  MergeRequestChanges,\n  Note,\n} from \"./types.js\";\n\nexport async function getMergeRequest(\n  client: GitlabClient,\n  projectId: string | number,\n  mergeRequestIid: number,\n): Promise<MergeRequest> {\n  const id = encodeProjectId(projectId);\n  return client.request<MergeRequest>(\n    \"GET\",\n    `/projects/${id}/merge_requests/${mergeRequestIid}`,\n  );\n}\n\nexport async function listMergeRequestNotes(\n  client: GitlabClient,\n  projectId: string | number,\n  mergeRequestIid: number,\n): Promise<Note[]> {\n  const id = encodeProjectId(projectId);\n  return client.requestAllPages<Note>(\n    `/projects/${id}/merge_requests/${mergeRequestIid}/notes`,\n  );\n}\n\n/** Create a general (non-inline) note on the merge request. Requires API token with write access. */\nexport async function createMergeRequestNote(\n  client: GitlabClient,\n  projectId: string | number,\n  mergeRequestIid: number,\n  params: { body: string },\n): Promise<Note> {\n  const id = encodeProjectId(projectId);\n  return client.request<Note>(\n    \"POST\",\n    `/projects/${id}/merge_requests/${mergeRequestIid}/notes`,\n    { body: params },\n  );\n}\n\nexport async function getMergeRequestChanges(\n  client: GitlabClient,\n  projectId: string | number,\n  mergeRequestIid: number,\n): Promise<MergeRequestChanges> {\n  const id = encodeProjectId(projectId);\n  return client.request<MergeRequestChanges>(\n    \"GET\",\n    `/projects/${id}/merge_requests/${mergeRequestIid}/changes`,\n  );\n}\n\nexport async function listMergeRequestCommits(\n  client: GitlabClient,\n  projectId: string | number,\n  mergeRequestIid: number,\n): Promise<Commit[]> {\n  const id = encodeProjectId(projectId);\n  return client.requestAllPages<Commit>(\n    `/projects/${id}/merge_requests/${mergeRequestIid}/commits`,\n  );\n}\n\nexport async function listMergeRequestDiscussions(\n  client: GitlabClient,\n  projectId: string | number,\n  mergeRequestIid: number,\n): Promise<\n  Array<{\n    id: string;\n    individual_note: boolean;\n    notes?: Note[];\n  }>\n> {\n  const id = encodeProjectId(projectId);\n  return client.requestAllPages(\n    `/projects/${id}/merge_requests/${mergeRequestIid}/discussions`,\n  );\n}\n", "import type { GitlabClient } from \"./client.js\";\nimport { encodeProjectId } from \"./encoding.js\";\nimport type { Pipeline, PipelineJob } from \"./types.js\";\n\nexport async function listPipelines(\n  client: GitlabClient,\n  projectId: string | number,\n  query?: Record<string, string | number | boolean | undefined>,\n): Promise<Pipeline[]> {\n  const id = encodeProjectId(projectId);\n  return client.requestAllPages<Pipeline>(\n    `/projects/${id}/pipelines`,\n    query ?? {},\n  );\n}\n\nexport async function getPipeline(\n  client: GitlabClient,\n  projectId: string | number,\n  pipelineId: number,\n): Promise<Pipeline> {\n  const id = encodeProjectId(projectId);\n  return client.request<Pipeline>(\n    \"GET\",\n    `/projects/${id}/pipelines/${pipelineId}`,\n  );\n}\n\nexport async function listPipelineJobs(\n  client: GitlabClient,\n  projectId: string | number,\n  pipelineId: number,\n  query?: Record<string, string | number | boolean | undefined>,\n): Promise<PipelineJob[]> {\n  const id = encodeProjectId(projectId);\n  return client.requestAllPages<PipelineJob>(\n    `/projects/${id}/pipelines/${pipelineId}/jobs`,\n    query ?? {},\n  );\n}\n\nexport async function getJob(\n  client: GitlabClient,\n  projectId: string | number,\n  jobId: number,\n): Promise<PipelineJob> {\n  const id = encodeProjectId(projectId);\n  return client.request<PipelineJob>(\"GET\", `/projects/${id}/jobs/${jobId}`);\n}\n\n/**\n * Raw CI job log / trace (plain text).\n * See [Get a log file](https://docs.gitlab.com/ee/api/jobs.html#get-a-log-file).\n */\nexport async function getJobTrace(\n  client: GitlabClient,\n  projectId: string | number,\n  jobId: number,\n): Promise<string> {\n  const id = encodeProjectId(projectId);\n  return client.requestText(\"GET\", `/projects/${id}/jobs/${jobId}/trace`);\n}\n", "import type { GitlabClient } from \"./client.js\";\nimport { encodeProjectId } from \"./encoding.js\";\nimport type { Blob, Commit, Note, RepositoryCompare } from \"./types.js\";\n\nexport async function listCommits(\n  client: GitlabClient,\n  projectId: string | number,\n  query?: { ref_name?: string; path?: string; since?: string; until?: string },\n): Promise<Commit[]> {\n  const id = encodeProjectId(projectId);\n  return client.requestAllPages<Commit>(\n    `/projects/${id}/repository/commits`,\n    query ?? {},\n  );\n}\n\nexport async function listCommitComments(\n  client: GitlabClient,\n  projectId: string | number,\n  sha: string,\n): Promise<Note[]> {\n  const id = encodeProjectId(projectId);\n  return client.requestAllPages<Note>(\n    `/projects/${id}/repository/commits/${sha}/comments`,\n  );\n}\n\n/**\n * Post a comment on a commit (SHA). GitLab expects JSON `{ \"note\": \"...\" }`.\n * Requires a token with the **`api`** scope (same as other write helpers).\n * See [Post comment to commit](https://docs.gitlab.com/ee/api/commits.html#post-comment-to-commit).\n */\nexport async function createCommitNote(\n  client: GitlabClient,\n  projectId: string | number,\n  sha: string,\n  params: { note: string },\n): Promise<Note> {\n  const id = encodeProjectId(projectId);\n  const shaSeg = encodeURIComponent(sha);\n  return client.request<Note>(\n    \"POST\",\n    `/projects/${id}/repository/commits/${shaSeg}/comments`,\n    { body: params },\n  );\n}\n\nexport async function getFile(\n  client: GitlabClient,\n  projectId: string | number,\n  filePath: string,\n  ref: string,\n): Promise<Blob> {\n  const id = encodeProjectId(projectId);\n  return client.request<Blob>(\n    \"GET\",\n    `/projects/${id}/repository/files/${encodeURIComponent(filePath.trim())}`,\n    {\n      query: { ref },\n    },\n  );\n}\n\nexport async function compareRefs(\n  client: GitlabClient,\n  projectId: string | number,\n  from: string,\n  to: string,\n): Promise<RepositoryCompare> {\n  const id = encodeProjectId(projectId);\n  return client.request<RepositoryCompare>(\n    \"GET\",\n    `/projects/${id}/repository/compare`,\n    {\n      query: { from, to },\n    },\n  );\n}\n", "import type { GitlabClient } from \"./client.js\";\nimport { encodeProjectId } from \"./encoding.js\";\nimport { getFile } from \"./repository.js\";\nimport type { Project } from \"./types.js\";\n\nexport async function getProject(\n  client: GitlabClient,\n  projectId: string | number,\n): Promise<Project> {\n  const id = encodeProjectId(projectId);\n  return client.request<Project>(\"GET\", `/projects/${id}`);\n}\n\n/** Fetch README (or any doc) via Repository Files API \u2014 scrub secrets before sending to models. */\nexport function getReadmeFile(\n  client: GitlabClient,\n  projectId: string | number,\n  filePath: string,\n  ref: string,\n): ReturnType<typeof getFile> {\n  return getFile(client, projectId, filePath, ref);\n}\n", "import type { GitlabClient } from \"./client.js\";\nimport { encodeProjectId } from \"./encoding.js\";\nimport { GitlabHttpError } from \"./errors.js\";\nimport type { Release } from \"./types.js\";\n\nexport async function getReleaseByTag(\n  client: GitlabClient,\n  projectId: string | number,\n  tagName: string,\n): Promise<Release> {\n  const id = encodeProjectId(projectId);\n  return client.request<Release>(\n    \"GET\",\n    `/projects/${id}/releases/${encodeURIComponent(tagName)}`,\n  );\n}\n\nexport async function listReleases(\n  client: GitlabClient,\n  projectId: string | number,\n): Promise<Release[]> {\n  const id = encodeProjectId(projectId);\n  return client.requestAllPages<Release>(`/projects/${id}/releases`);\n}\n\nexport type UpsertReleaseParams = {\n  description: string;\n  /** Display name in GitLab. When creating a release, defaults to `tagName` if omitted. */\n  name?: string;\n  /**\n   * When **creating** a release and the Git tag does not exist yet, branch or commit SHA to create it from.\n   * Omit if the tag already exists in the repository.\n   */\n  ref?: string;\n};\n\n/**\n * Create or update a project release for `tagName`.\n * If no release exists for the tag, `POST` is used; otherwise `PUT`. Requires API token with write access.\n */\nexport async function upsertRelease(\n  client: GitlabClient,\n  projectId: string | number,\n  tagName: string,\n  params: UpsertReleaseParams,\n): Promise<Release> {\n  const id = encodeProjectId(projectId);\n  const pathTag = encodeURIComponent(tagName);\n\n  let existing: Release | null = null;\n  try {\n    existing = await getReleaseByTag(client, projectId, tagName);\n  } catch (e) {\n    if (e instanceof GitlabHttpError && e.status === 404) {\n      existing = null;\n    } else {\n      throw e;\n    }\n  }\n\n  if (existing) {\n    return client.request<Release>(\n      \"PUT\",\n      `/projects/${id}/releases/${pathTag}`,\n      {\n        body: {\n          description: params.description,\n          ...(params.name !== undefined ? { name: params.name } : {}),\n        },\n      },\n    );\n  }\n\n  return client.request<Release>(\"POST\", `/projects/${id}/releases`, {\n    body: {\n      tag_name: tagName,\n      description: params.description,\n      name: params.name ?? tagName,\n      ...(params.ref !== undefined ? { ref: params.ref } : {}),\n    },\n  });\n}\n", "import type { GitlabClient } from \"./client.js\";\n\nexport type SearchScope =\n  | \"projects\"\n  | \"issues\"\n  | \"merge_requests\"\n  | \"milestones\"\n  | \"snippet_titles\"\n  | \"wiki_blobs\"\n  | \"commits\"\n  | \"blobs\";\n\n/** Global search (optionally scoped to a project or group). */\nexport async function searchGitlab(\n  client: GitlabClient,\n  options: {\n    scope: SearchScope;\n    search: string;\n    projectId?: string | number;\n    groupId?: string | number;\n    additional?: Record<string, string | number | boolean | undefined>;\n  },\n): Promise<unknown[]> {\n  const query: Record<string, string | number | boolean | undefined> = {\n    scope: options.scope,\n    search: options.search,\n    ...options.additional,\n  };\n  if (options.projectId !== undefined) {\n    query.project_id = options.projectId;\n  }\n  if (options.groupId !== undefined) {\n    query.group_id = options.groupId;\n  }\n  return client.requestAllPages<unknown>(\"/search\", query);\n}\n\nexport async function searchInProject(\n  client: GitlabClient,\n  projectId: string | number,\n  scope: SearchScope,\n  search: string,\n): Promise<unknown[]> {\n  return searchGitlab(client, {\n    scope,\n    search,\n    projectId,\n  });\n}\n\nexport async function searchInGroup(\n  client: GitlabClient,\n  groupId: string | number,\n  scope: SearchScope,\n  search: string,\n): Promise<unknown[]> {\n  return searchGitlab(client, {\n    scope,\n    search,\n    groupId,\n  });\n}\n", "import type { GitlabClient } from \"./client.js\";\nimport { encodeProjectId } from \"./encoding.js\";\nimport type { VulnerabilityFinding } from \"./types.js\";\n\n/** Project vulnerability findings (report_type varies by scanner). */\nexport async function listVulnerabilityFindings(\n  client: GitlabClient,\n  projectId: string | number,\n  query?: Record<string, string | number | boolean | undefined>,\n): Promise<VulnerabilityFinding[]> {\n  const id = encodeProjectId(projectId);\n  return client.requestAllPages<VulnerabilityFinding>(\n    `/projects/${id}/vulnerability_findings`,\n    query ?? {},\n  );\n}\n", "import type { GitlabClient } from \"./client.js\";\nimport { encodeProjectId } from \"./encoding.js\";\nimport { GitlabHttpError } from \"./errors.js\";\nimport type { Snippet, WikiPage } from \"./types.js\";\n\nexport async function listWikiPages(\n  client: GitlabClient,\n  projectId: string | number,\n): Promise<Array<{ format?: string; slug: string; title: string }>> {\n  const id = encodeProjectId(projectId);\n  return client.request(\"GET\", `/projects/${id}/wikis`);\n}\n\nexport async function getWikiPage(\n  client: GitlabClient,\n  projectId: string | number,\n  slug: string,\n  version?: string,\n): Promise<WikiPage> {\n  const id = encodeProjectId(projectId);\n  const path = `/projects/${id}/wikis/${encodeURIComponent(slug)}`;\n  return client.request<WikiPage>(\"GET\", path, {\n    query: version ? { version } : undefined,\n  });\n}\n\nexport type CreateWikiPageParams = {\n  title: string;\n  content: string;\n  /** Default when omitted: `markdown`. */\n  format?: string;\n};\n\n/** Create a wiki page (`POST /projects/:id/wikis`). Requires API token with write access. */\nexport async function createWikiPage(\n  client: GitlabClient,\n  projectId: string | number,\n  params: CreateWikiPageParams,\n): Promise<WikiPage> {\n  const id = encodeProjectId(projectId);\n  return client.request<WikiPage>(\"POST\", `/projects/${id}/wikis`, {\n    body: {\n      title: params.title,\n      content: params.content,\n      ...(params.format !== undefined ? { format: params.format } : {}),\n    },\n  });\n}\n\nexport type UpdateWikiPageParams = {\n  content?: string;\n  title?: string;\n  format?: string;\n};\n\n/** Update a wiki page by slug (`PUT /projects/:id/wikis/:slug`). Requires API token with write access. */\nexport async function updateWikiPage(\n  client: GitlabClient,\n  projectId: string | number,\n  slug: string,\n  params: UpdateWikiPageParams,\n): Promise<WikiPage> {\n  const id = encodeProjectId(projectId);\n  const path = `/projects/${id}/wikis/${encodeURIComponent(slug)}`;\n  const body: Record<string, string> = {};\n  if (params.content !== undefined) {\n    body.content = params.content;\n  }\n  if (params.title !== undefined) {\n    body.title = params.title;\n  }\n  if (params.format !== undefined) {\n    body.format = params.format;\n  }\n  return client.request<WikiPage>(\"PUT\", path, { body });\n}\n\nexport type UpsertWikiPageParams = {\n  content: string;\n  /** Used when creating a new page; defaults to `slug` if omitted. */\n  title?: string;\n  format?: string;\n};\n\n/**\n * Create or update a wiki page at `slug`: `GET` first; on 404 `POST` (create), else `PUT` (update).\n * GitLab derives the URL slug from `title` on create; pass a `title` consistent with the desired slug.\n */\nexport async function upsertWikiPage(\n  client: GitlabClient,\n  projectId: string | number,\n  slug: string,\n  params: UpsertWikiPageParams,\n): Promise<WikiPage> {\n  let existing: WikiPage | null = null;\n  try {\n    existing = await getWikiPage(client, projectId, slug);\n  } catch (e) {\n    if (e instanceof GitlabHttpError && e.status === 404) {\n      existing = null;\n    } else {\n      throw e;\n    }\n  }\n\n  if (existing) {\n    return updateWikiPage(client, projectId, slug, {\n      content: params.content,\n      ...(params.title !== undefined ? { title: params.title } : {}),\n      ...(params.format !== undefined ? { format: params.format } : {}),\n    });\n  }\n\n  return createWikiPage(client, projectId, {\n    title: params.title ?? slug,\n    content: params.content,\n    format: params.format,\n  });\n}\n\nexport async function listProjectSnippets(\n  client: GitlabClient,\n  projectId: string | number,\n): Promise<Snippet[]> {\n  const id = encodeProjectId(projectId);\n  return client.requestAllPages<Snippet>(`/projects/${id}/snippets`);\n}\n\nexport async function getSnippet(\n  client: GitlabClient,\n  snippetId: number,\n): Promise<Snippet & { blob?: { raw_path?: string } }> {\n  return client.request(\"GET\", `/snippets/${snippetId}`);\n}\n", "import { POLICY_DEFAULT } from \"../ai/policies.js\";\nimport { truncateForPrompt } from \"../ai/textLimits.js\";\nimport type { LabflowLlm } from \"../ai/types.js\";\nimport type { GitlabClient } from \"../gitlab/client.js\";\nimport { listGroupEvents, listProjectEvents } from \"../gitlab/events.js\";\n\nfunction formatEvent(e: {\n  action_name?: string;\n  target_type?: string;\n  target_title?: string;\n  created_at?: string;\n  author?: { username?: string };\n}): string {\n  return `[${e.created_at ?? \"\"}] ${e.author?.username ?? \"?\"} ${e.action_name ?? \"\"} ${e.target_type ?? \"\"} \u2014 ${e.target_title ?? \"\"}`;\n}\n\n/** Weekly-style digest; dedupe is LLM-assisted (caller should pre-filter if needed). */\nexport async function aiProjectWeeklyDigest(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  options?: { model?: string; maxPromptChars?: number },\n): Promise<string> {\n  const events = await listProjectEvents(client, projectId, { per_page: 100 });\n  const raw = events.map(formatEvent).join(\"\\n\");\n  const user = truncateForPrompt(raw, options?.maxPromptChars ?? 100_000);\n\n  return llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nWrite a concise weekly \"what happened\" digest for the project. Deduplicate noise. Markdown.`,\n    user,\n  });\n}\n\nexport async function aiGroupWeeklyDigest(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  groupId: string | number,\n  options?: { model?: string; maxPromptChars?: number },\n): Promise<string> {\n  const events = await listGroupEvents(client, groupId, { per_page: 100 });\n  const raw = events.map(formatEvent).join(\"\\n\");\n  const user = truncateForPrompt(raw, options?.maxPromptChars ?? 100_000);\n\n  return llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nWrite a concise weekly digest for the group. Markdown.`,\n    user,\n  });\n}\n", "import { POLICY_DEFAULT } from \"../ai/policies.js\";\nimport { truncateForPrompt } from \"../ai/textLimits.js\";\nimport type { LabflowLlm } from \"../ai/types.js\";\nimport type { GitlabClient } from \"../gitlab/client.js\";\nimport { listDeployments, listEnvironments } from \"../gitlab/deployments.js\";\n\nexport async function aiPostDeployIncidentBrief(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  options?: {\n    model?: string;\n    maxPromptChars?: number;\n    environment?: string;\n    perPage?: number;\n  },\n): Promise<string> {\n  const deps = await listDeployments(client, projectId, {\n    environment: options?.environment,\n    per_page: options?.perPage ?? 30,\n  });\n  const envs = await listEnvironments(client, projectId);\n\n  const block = [\n    \"## Recent deployments\",\n    ...deps\n      .slice(0, 20)\n      .map(\n        (d) =>\n          `- ${d.updated_at ?? d.created_at ?? \"\"} ${d.status} ${d.environment?.name ?? \"\"} ${d.sha ?? d.ref ?? \"\"}`,\n      ),\n    \"## Environments\",\n    ...envs.map((e) => `- ${e.name}: ${e.state ?? \"\"}`),\n  ].join(\"\\n\");\n\n  const user = truncateForPrompt(block, options?.maxPromptChars ?? 60_000);\n\n  return llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nDraft a post-deploy incident brief scaffold: what shipped, what to watch, rollback hooks to verify. Not infra deep. Markdown.`,\n    user,\n  });\n}\n", "import { POLICY_DEFAULT } from \"../ai/policies.js\";\nimport { truncateForPrompt } from \"../ai/textLimits.js\";\nimport type { LabflowLlm } from \"../ai/types.js\";\nimport type { GitlabClient } from \"../gitlab/client.js\";\nimport { getEpic, listEpicIssues } from \"../gitlab/epics.js\";\n\nexport async function aiEpicRoadmapRollup(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  groupId: string | number,\n  epicIid: number,\n  options?: { model?: string; maxPromptChars?: number },\n): Promise<string> {\n  const epic = await getEpic(client, groupId, epicIid);\n  const issues = await listEpicIssues(client, groupId, epicIid);\n\n  const head = `${epic.title}\\n${epic.description ?? \"\"}\\nState: ${epic.state ?? \"\"}`;\n  const issueLines = issues\n    .map((i) => `- #${i.iid} ${i.title} (${i.state ?? \"?\"})`)\n    .join(\"\\n\");\n\n  const user = truncateForPrompt(\n    `${head}\\n\\n## Child issues\\n${issueLines}`,\n    options?.maxPromptChars ?? 80_000,\n  );\n\n  return llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nProduce a roadmap-style rollup: status themes, dependencies, risks, suggested sequencing. Markdown.`,\n    user,\n  });\n}\n", "import { POLICY_DEFAULT } from \"../ai/policies.js\";\nimport { truncateForPrompt } from \"../ai/textLimits.js\";\nimport type { LabflowLlm } from \"../ai/types.js\";\nimport type { GitlabClient } from \"../gitlab/client.js\";\nimport {\n  createIssueNote,\n  getIssue,\n  listIssueNotes,\n  listProjectIssues,\n} from \"../gitlab/issues.js\";\nimport type { Issue } from \"../gitlab/types.js\";\n\nfunction formatIssueHeader(issue: Issue): string {\n  const labels = Array.isArray(issue.labels)\n    ? issue.labels.map((l) => (typeof l === \"string\" ? l : l.name))\n    : [];\n  return [\n    `Title: ${issue.title}`,\n    issue.description ?? \"\",\n    `State: ${issue.state}`,\n    labels.length ? `Labels: ${labels.join(\", \")}` : \"\",\n    issue.web_url ? `URL: ${issue.web_url}` : \"\",\n    issue.created_at ? `Created: ${issue.created_at}` : \"\",\n    issue.updated_at ? `Updated: ${issue.updated_at}` : \"\",\n  ]\n    .filter(Boolean)\n    .join(\"\\n\");\n}\n\nfunction formatNote(n: {\n  body?: string;\n  author?: { username?: string; name?: string };\n  created_at?: string;\n}): string {\n  const who = n.author?.username ?? n.author?.name ?? \"?\";\n  return `[${n.created_at ?? \"\"}] @${who}: ${n.body ?? \"\"}`;\n}\n\nexport type AiIssueInsightOptions = {\n  model?: string;\n  maxPromptChars?: number;\n  /** When true, POST the generated summary as a new issue note (requires token with API write access). */\n  postSummaryAsIssueNote?: boolean;\n};\n\nasync function maybePostIssueSummary(\n  client: GitlabClient,\n  projectId: string | number,\n  issueIid: number,\n  summary: string,\n  post: boolean | undefined,\n): Promise<void> {\n  if (!post) {\n    return;\n  }\n  await createIssueNote(client, projectId, issueIid, { body: summary });\n}\n\nexport async function aiIssueThreadSummary(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  issueIid: number,\n  options?: AiIssueInsightOptions,\n): Promise<string> {\n  const issue = await getIssue(client, projectId, issueIid);\n  const notes = await listIssueNotes(client, projectId, issueIid);\n  const user = truncateForPrompt(\n    `${formatIssueHeader(issue)}\\n\\n## Comments\\n${notes.map(formatNote).join(\"\\n\\n\")}`,\n    options?.maxPromptChars ?? 100_000,\n  );\n\n  const summary = await llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nSummarize a long issue thread: decisions, blockers, next steps. Markdown.`,\n    user,\n  });\n  await maybePostIssueSummary(\n    client,\n    projectId,\n    issueIid,\n    summary,\n    options?.postSummaryAsIssueNote,\n  );\n  return summary;\n}\n\nexport async function aiStaleIssueSummary(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  issueIid: number,\n  options?: AiIssueInsightOptions,\n): Promise<string> {\n  const issue = await getIssue(client, projectId, issueIid);\n  const notes = await listIssueNotes(client, projectId, issueIid);\n  const user = truncateForPrompt(\n    `${formatIssueHeader(issue)}\\n\\n## Comments\\n${notes.map(formatNote).join(\"\\n\\n\")}`,\n    options?.maxPromptChars ?? 100_000,\n  );\n\n  const summary = await llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nAssess staleness: lastactivity, unclear ownership, recommended ping or close criteria. Markdown.`,\n    user,\n  });\n  await maybePostIssueSummary(\n    client,\n    projectId,\n    issueIid,\n    summary,\n    options?.postSummaryAsIssueNote,\n  );\n  return summary;\n}\n\nexport async function aiIssueSuggestedNextStep(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  issueIid: number,\n  options?: AiIssueInsightOptions,\n): Promise<string> {\n  const issue = await getIssue(client, projectId, issueIid);\n  const notes = await listIssueNotes(client, projectId, issueIid);\n  const user = truncateForPrompt(\n    `${formatIssueHeader(issue)}\\n\\n## Comments\\n${notes.map(formatNote).join(\"\\n\\n\")}`,\n    options?.maxPromptChars ?? 100_000,\n  );\n\n  const summary = await llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nPropose the smallest next step toward resolution and closure criteria. Markdown checklist.`,\n    user,\n  });\n  await maybePostIssueSummary(\n    client,\n    projectId,\n    issueIid,\n    summary,\n    options?.postSummaryAsIssueNote,\n  );\n  return summary;\n}\n\n/** Scan open issues for likely stale work (heuristic; then optionally batch LLM per issue). */\nexport async function listOpenIssuesForProject(\n  client: GitlabClient,\n  projectId: string | number,\n  state: \"opened\" | \"closed\" = \"opened\",\n): Promise<Issue[]> {\n  return listProjectIssues(client, projectId, { state });\n}\n", "import { POLICY_DEFAULT } from \"../ai/policies.js\";\nimport { truncateForPrompt } from \"../ai/textLimits.js\";\nimport type { LabflowLlm } from \"../ai/types.js\";\nimport type { GitlabClient } from \"../gitlab/client.js\";\nimport {\n  createMergeRequestNote,\n  getMergeRequest,\n  listMergeRequestDiscussions,\n  listMergeRequestNotes,\n} from \"../gitlab/mergeRequests.js\";\nimport type { MergeRequest, Note } from \"../gitlab/types.js\";\n\nfunction formatNote(n: Note): string {\n  const who = n.author?.username ?? n.author?.name ?? \"?\";\n  const when = n.created_at ?? \"\";\n  return `[${when}] @${who}: ${n.body ?? \"\"}`;\n}\n\nfunction formatMrHeader(mr: MergeRequest): string {\n  const labels = Array.isArray(mr.labels)\n    ? mr.labels.map((l) => (typeof l === \"string\" ? l : l.name))\n    : [];\n  const assignees = (mr.assignees ?? [])\n    .map((a) => a.username ?? a.name)\n    .join(\", \");\n  return [\n    `Title: ${mr.title}`,\n    mr.description ? `Description:\\n${mr.description}` : \"\",\n    `State: ${mr.state}; branches: ${mr.source_branch ?? \"?\"} \u2192 ${mr.target_branch ?? \"?\"}`,\n    labels.length ? `Labels: ${labels.join(\", \")}` : \"\",\n    assignees ? `Assignees: ${assignees}` : \"\",\n    mr.web_url ? `URL: ${mr.web_url}` : \"\",\n  ]\n    .filter(Boolean)\n    .join(\"\\n\");\n}\n\nexport type AiMergeRequestInsightOptions = {\n  model?: string;\n  maxPromptChars?: number;\n  /** When true, POST the generated summary as a new merge request note (requires token with API write access). */\n  postSummaryAsMergeRequestNote?: boolean;\n};\n\nasync function maybePostMergeRequestSummary(\n  client: GitlabClient,\n  projectId: string | number,\n  mergeRequestIid: number,\n  summary: string,\n  post: boolean | undefined,\n): Promise<void> {\n  if (!post) {\n    return;\n  }\n  await createMergeRequestNote(client, projectId, mergeRequestIid, {\n    body: summary,\n  });\n}\n\n/** Compact digest of MR discussion (title, description, all notes / discussion threads). */\nexport async function aiMergeRequestDiscussionDigest(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  mergeRequestIid: number,\n  options?: AiMergeRequestInsightOptions,\n): Promise<string> {\n  const mr = await getMergeRequest(client, projectId, mergeRequestIid);\n  const [notes, discussions] = await Promise.all([\n    listMergeRequestNotes(client, projectId, mergeRequestIid),\n    listMergeRequestDiscussions(client, projectId, mergeRequestIid),\n  ]);\n\n  const notesBlock = notes.map(formatNote).join(\"\\n\\n\");\n  const discBlock = discussions\n    .map((d, i) => {\n      const thread = (d.notes ?? []).map(formatNote).join(\"\\n\");\n      return `Thread ${i + 1} (${d.id}):\\n${thread}`;\n    })\n    .join(\"\\n\\n---\\n\\n\");\n\n  const raw = `${formatMrHeader(mr)}\\n\\n## Notes\\n${notesBlock}\\n\\n## Discussions\\n${discBlock}`;\n  const user = truncateForPrompt(raw, options?.maxPromptChars ?? 100_000);\n\n  const summary = await llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nSummarize merge request discussion for a busy reviewer: themes, decisions, open questions. Markdown.`,\n    user,\n  });\n  await maybePostMergeRequestSummary(\n    client,\n    projectId,\n    mergeRequestIid,\n    summary,\n    options?.postSummaryAsMergeRequestNote,\n  );\n  return summary;\n}\n\nexport type ReviewSinceOptions = {\n  /** Only include notes/discussion replies strictly after this ISO timestamp (exclusive). */\n  sinceIso?: string;\n};\n\n/** Highlights what changed in discussion since a prior review checkpoint. */\nexport async function aiWhatChangedSinceLastReview(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  mergeRequestIid: number,\n  since: ReviewSinceOptions,\n  options?: AiMergeRequestInsightOptions,\n): Promise<string> {\n  const mr = await getMergeRequest(client, projectId, mergeRequestIid);\n  const notes = await listMergeRequestNotes(client, projectId, mergeRequestIid);\n  const cut = since.sinceIso ? Date.parse(since.sinceIso) : NaN;\n  const filtered =\n    Number.isFinite(cut) && !Number.isNaN(cut)\n      ? notes.filter((n) => {\n          if (!n.created_at) {\n            return true;\n          }\n          return Date.parse(n.created_at) > cut;\n        })\n      : notes;\n\n  const user = truncateForPrompt(\n    `${formatMrHeader(mr)}\\n\\n## New notes since checkpoint\\n${filtered.map(formatNote).join(\"\\n\\n\")}`,\n    options?.maxPromptChars ?? 80_000,\n  );\n\n  const summary = await llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nList only new information since the reviewer last looked: new commits mentioned, replies, resolutions. Bulleted Markdown.`,\n    user,\n  });\n  await maybePostMergeRequestSummary(\n    client,\n    projectId,\n    mergeRequestIid,\n    summary,\n    options?.postSummaryAsMergeRequestNote,\n  );\n  return summary;\n}\n\n/** Draft reply text the author/reviewer could post (non-authoritative). */\nexport async function aiSuggestedMergeRequestReply(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  mergeRequestIid: number,\n  context: {\n    /** What the reply should address (e.g. last thread excerpt). */\n    inReplyTo?: string;\n    tone?: \"neutral\" | \"friendly\" | \"concise\";\n  },\n  options?: AiMergeRequestInsightOptions,\n): Promise<string> {\n  const mr = await getMergeRequest(client, projectId, mergeRequestIid);\n  const notes = await listMergeRequestNotes(client, projectId, mergeRequestIid);\n  const tail = notes.slice(-15);\n  const user = truncateForPrompt(\n    `${formatMrHeader(mr)}\\n\\nRecent notes:\\n${tail.map(formatNote).join(\"\\n\\n\")}\\n\\nReply target:\\n${context.inReplyTo ?? \"(not specified)\"}`,\n    options?.maxPromptChars ?? 80_000,\n  );\n\n  const summary = await llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nDraft a short GitLab comment (${context.tone ?? \"neutral\"}). Do not claim approvals or CI passed unless stated in the thread. Markdown, code blocks only when needed.`,\n    user,\n  });\n  await maybePostMergeRequestSummary(\n    client,\n    projectId,\n    mergeRequestIid,\n    summary,\n    options?.postSummaryAsMergeRequestNote,\n  );\n  return summary;\n}\n\n/** Bullet list of action items extracted from MR + discussion. */\nexport async function aiMergeRequestActionItems(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  mergeRequestIid: number,\n  options?: AiMergeRequestInsightOptions,\n): Promise<string> {\n  const mr = await getMergeRequest(client, projectId, mergeRequestIid);\n  const [notes, discussions] = await Promise.all([\n    listMergeRequestNotes(client, projectId, mergeRequestIid),\n    listMergeRequestDiscussions(client, projectId, mergeRequestIid),\n  ]);\n\n  const discText = discussions\n    .flatMap((d) => d.notes ?? [])\n    .map(formatNote)\n    .join(\"\\n\");\n\n  const raw = `${formatMrHeader(mr)}\\n\\n${notes.map(formatNote).join(\"\\n\\n\")}\\n\\n${discText}`;\n  const user = truncateForPrompt(raw, options?.maxPromptChars ?? 100_000);\n\n  const summary = await llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nExtract concrete action items (owner if known, else TBD). Checklist Markdown.`,\n    user,\n  });\n  await maybePostMergeRequestSummary(\n    client,\n    projectId,\n    mergeRequestIid,\n    summary,\n    options?.postSummaryAsMergeRequestNote,\n  );\n  return summary;\n}\n\n/**\n * Narrative reviewer briefing using MR metadata (labels, assignees, branches) without diff text.\n * Pair with {@link summarizeMergeRequestDiffWithSmartDiff} for risk + change summary.\n */\nexport async function aiMergeRequestReviewerBriefingMeta(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  mergeRequestIid: number,\n  options?: AiMergeRequestInsightOptions,\n): Promise<string> {\n  const mr = await getMergeRequest(client, projectId, mergeRequestIid);\n  const user = truncateForPrompt(\n    `${formatMrHeader(mr)}`,\n    options?.maxPromptChars ?? 16_000,\n  );\n\n  const summary = await llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nWrite a short reviewer briefing: context, blast radius guess from title/branches/labels, questions to ask. Markdown. No diff content provided.`,\n    user,\n  });\n  await maybePostMergeRequestSummary(\n    client,\n    projectId,\n    mergeRequestIid,\n    summary,\n    options?.postSummaryAsMergeRequestNote,\n  );\n  return summary;\n}\n", "import {\n  POLICY_DEFAULT,\n  POLICY_NO_SECRET_EXFILTRATION,\n} from \"../ai/policies.js\";\nimport { truncateForPrompt } from \"../ai/textLimits.js\";\nimport type { LabflowLlm } from \"../ai/types.js\";\nimport type { GitlabClient } from \"../gitlab/client.js\";\nimport {\n  getJob,\n  getJobTrace,\n  getPipeline,\n  listPipelineJobs,\n} from \"../gitlab/pipelines.js\";\nimport type { PipelineJob } from \"../gitlab/types.js\";\n\nfunction jobNeedsFailureAnalysis(status: string): boolean {\n  return status === \"failed\" || status === \"canceled\";\n}\n\nexport type AiPipelineInsightOptions = {\n  model?: string;\n  maxPromptChars?: number;\n  /**\n   * Max characters of log text per job when attaching traces (default 32_000).\n   * Applied before the global {@link maxPromptChars} cap.\n   */\n  maxTraceCharsPerJob?: number;\n  /**\n   * When true (default), fetch and attach job logs only for failed or canceled jobs.\n   * When false, attach a truncated trace for every job (can be very large).\n   */\n  tracesForFailedJobsOnly?: boolean;\n};\n\nfunction formatJobHeader(j: PipelineJob): string {\n  const url = j.web_url ? ` ${j.web_url}` : \"\";\n  const fr = j.failure_reason ? ` failure_reason=${j.failure_reason}` : \"\";\n  return `- [${j.stage ?? \"stage?\"}] ${j.name} \u2014 ${j.status}${fr}${url}`;\n}\n\n/**\n * Summarize a single CI job log: what happened, errors, and likely root cause if it failed.\n */\nexport async function aiPipelineJobLogSummary(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  jobId: number,\n  options?: AiPipelineInsightOptions,\n): Promise<string> {\n  const job = await getJob(client, projectId, jobId);\n  const trace = await getJobTrace(client, projectId, jobId).catch(() => \"\");\n  const perJobCap = options?.maxTraceCharsPerJob ?? 32_000;\n  const logBlock = truncateForPrompt(trace, perJobCap);\n\n  const user = [\n    \"## Job metadata\",\n    formatJobHeader(job),\n    job.ref ? `ref: ${job.ref}` : \"\",\n    job.started_at ? `started_at: ${job.started_at}` : \"\",\n    job.finished_at ? `finished_at: ${job.finished_at}` : \"\",\n    \"## Job log (trace)\",\n    logBlock || \"(empty or unavailable)\",\n  ]\n    .filter(Boolean)\n    .join(\"\\n\");\n\n  const prompt = truncateForPrompt(user, options?.maxPromptChars ?? 120_000);\n\n  return llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\n${POLICY_NO_SECRET_EXFILTRATION}\\nYou are reviewing a GitLab CI job log.\\nSummarize in Markdown: purpose of the job, key steps, outcome, and if it failed the most likely root cause and concrete next checks. If the log was truncated, say so. Do not invent commands or URLs not supported by the log.`,\n    user: prompt,\n  });\n}\n\n/**\n * High-level summary of a pipeline run: stages, job outcomes, and for failures why they likely failed (from job logs).\n * Use this after a failed deployment or broken pipeline to get an LLM-readable brief.\n */\nexport async function aiPipelineRunSummary(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  pipelineId: number,\n  options?: AiPipelineInsightOptions,\n): Promise<string> {\n  const pipeline = await getPipeline(client, projectId, pipelineId);\n  const jobs = await listPipelineJobs(client, projectId, pipelineId);\n  const failedOnly = options?.tracesForFailedJobsOnly !== false;\n  const perJobCap = options?.maxTraceCharsPerJob ?? 32_000;\n\n  const lines: string[] = [\n    \"## Pipeline\",\n    `- id=${pipeline.id} iid=${pipeline.iid} status=${pipeline.status}`,\n    pipeline.ref ? `ref: ${pipeline.ref}` : \"\",\n    pipeline.sha ? `sha: ${pipeline.sha}` : \"\",\n    pipeline.web_url ? `url: ${pipeline.web_url}` : \"\",\n    \"\",\n    \"## Jobs (overview)\",\n    ...jobs.map((j) => formatJobHeader(j)),\n    \"\",\n  ].filter((x) => x !== \"\");\n\n  const traceSections: string[] = [];\n\n  for (const j of jobs) {\n    const wantTrace = failedOnly ? jobNeedsFailureAnalysis(j.status) : true;\n    if (!wantTrace) {\n      continue;\n    }\n    let trace = \"\";\n    try {\n      trace = await getJobTrace(client, projectId, j.id);\n    } catch {\n      trace = \"(trace unavailable)\";\n    }\n    const snippet = truncateForPrompt(trace, perJobCap);\n    traceSections.push(\n      `### Log: [${j.stage ?? \"?\"}] ${j.name} (${j.status})\\n${snippet}`,\n    );\n  }\n\n  if (traceSections.length > 0) {\n    lines.push(\"## Job logs\");\n    lines.push(...traceSections);\n  } else {\n    lines.push(\"## Job logs\");\n    lines.push(\n      \"(No failed or canceled jobs in this run \u2014 job logs were not attached. Pass `tracesForFailedJobsOnly: false` if you need full traces for every job.)\",\n    );\n  }\n\n  const user = truncateForPrompt(\n    lines.join(\"\\n\"),\n    options?.maxPromptChars ?? 120_000,\n  );\n\n  return llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\n${POLICY_NO_SECRET_EXFILTRATION}\\nYou are reviewing a GitLab CI pipeline and selected job logs.\\nProduce a concise Markdown brief: overall pipeline outcome, stage-by-stage picture, which jobs failed or were skipped, and for failures the likely root cause from the logs. If this run blocked a deployment, state that clearly. If logs are missing or truncated, say so. Do not invent failing commands or infrastructure details not present in the text.`,\n    user,\n  });\n}\n", "import {\n  POLICY_DEFAULT,\n  POLICY_NO_SECRET_EXFILTRATION,\n} from \"../ai/policies.js\";\nimport { truncateForPrompt } from \"../ai/textLimits.js\";\nimport type { LabflowLlm } from \"../ai/types.js\";\nimport type { GitlabClient } from \"../gitlab/client.js\";\nimport { getProject, getReadmeFile } from \"../gitlab/projectMeta.js\";\n\nexport async function aiProjectReadmeConsistency(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  options?: {\n    model?: string;\n    maxPromptChars?: number;\n    readmePath?: string;\n    ref?: string;\n  },\n): Promise<string> {\n  const project = await getProject(client, projectId);\n  const ref = options?.ref ?? project.default_branch ?? \"main\";\n  const readmePath = options?.readmePath ?? \"README.md\";\n  let readmeBody = \"\";\n  try {\n    const blob = await getReadmeFile(client, projectId, readmePath, ref);\n    readmeBody =\n      blob.encoding === \"base64\" && blob.content\n        ? Buffer.from(blob.content, \"base64\").toString(\"utf8\").slice(0, 60_000)\n        : (blob.content ?? \"\");\n  } catch {\n    readmeBody = \"(README not fetched \u2014 check branch/path permissions)\";\n  }\n\n  const meta = [\n    `Name: ${project.name ?? \"\"}`,\n    `Path: ${project.path_with_namespace ?? \"\"}`,\n    `Description: ${project.description ?? \"\"}`,\n    `Topics: ${(project.topics ?? []).join(\", \")}`,\n    `Default branch: ${project.default_branch ?? \"\"}`,\n    `Web: ${project.web_url ?? \"\"}`,\n  ].join(\"\\n\");\n\n  const user = truncateForPrompt(\n    `${meta}\\n\\n## README (${readmePath} @ ${ref})\\n${readmeBody}`,\n    options?.maxPromptChars ?? 100_000,\n  );\n\n  return llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\n${POLICY_NO_SECRET_EXFILTRATION}\\nCheck alignment between project metadata and README for onboarding blurbs (gaps, contradictions). Markdown.`,\n    user,\n  });\n}\n", "import { POLICY_DEFAULT } from \"../ai/policies.js\";\nimport { truncateForPrompt } from \"../ai/textLimits.js\";\nimport type { LabflowLlm } from \"../ai/types.js\";\nimport type { GitlabClient } from \"../gitlab/client.js\";\nimport {\n  getReleaseByTag,\n  listReleases,\n  upsertRelease,\n} from \"../gitlab/releases.js\";\nimport { compareRefs, listCommits } from \"../gitlab/repository.js\";\nimport { upsertWikiPage } from \"../gitlab/wikiAndSnippets.js\";\n\nexport type AiDraftReleaseNotesOptions = {\n  model?: string;\n  maxPromptChars?: number;\n  priorTag?: string;\n  /**\n   * When true, create or update the GitLab release for `tagName` with the generated markdown as `description`.\n   * Requires token with API write access (same privilege story as MR/issue notes).\n   */\n  postSummaryAsReleaseDescription?: boolean;\n  /** When creating a release and the Git tag does not exist yet, branch or SHA for `upsertRelease`. */\n  releaseRef?: string;\n  /** Display name for a newly created release; optional. */\n  releaseName?: string;\n};\n\nexport async function aiDraftReleaseNotes(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  tagName: string,\n  options?: AiDraftReleaseNotesOptions,\n): Promise<string> {\n  const release = await getReleaseByTag(client, projectId, tagName).catch(\n    () => null,\n  );\n  const prior = options?.priorTag;\n\n  let commitText = \"\";\n  if (prior) {\n    const cmp = await compareRefs(client, projectId, prior, tagName);\n    const commits = cmp.commits ?? [];\n    commitText = commits\n      .map((c) => `- ${c.id.slice(0, 8)} ${(c.message ?? \"\").split(\"\\n\")[0]}`)\n      .join(\"\\n\");\n  } else {\n    const commits = await listCommits(client, projectId, { ref_name: tagName });\n    commitText = commits\n      .slice(0, 50)\n      .map((c) => `- ${c.id.slice(0, 8)} ${(c.message ?? \"\").split(\"\\n\")[0]}`)\n      .join(\"\\n\");\n  }\n\n  const relDesc = release?.description ?? \"(no release description on GitLab)\";\n  const user = truncateForPrompt(\n    `Tag: ${tagName}\\nExisting GitLab release notes:\\n${relDesc}\\n\\nCommits in window:\\n${commitText}`,\n    options?.maxPromptChars ?? 100_000,\n  );\n\n  const summary = await llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nDraft improved release notes for humans: highlights, breaking changes if any, upgrade hints. This is a draft. Markdown.`,\n    user,\n  });\n\n  if (options?.postSummaryAsReleaseDescription) {\n    await upsertRelease(client, projectId, tagName, {\n      description: summary,\n      ref: options.releaseRef,\n      name: options.releaseName,\n    });\n  }\n\n  return summary;\n}\n\nexport type AiListReleasesOverviewOptions = {\n  model?: string;\n  maxPromptChars?: number;\n  /**\n   * When set, writes the generated overview to this wiki page slug (create or update via `upsertWikiPage`).\n   * Requires token with API write access.\n   */\n  postSummaryToWikiSlug?: string;\n  /** Page title when creating a new wiki page; defaults to `postSummaryToWikiSlug` if omitted. */\n  wikiPageTitle?: string;\n  /** Wiki format (e.g. `markdown`); passed through to `upsertWikiPage`. */\n  wikiFormat?: string;\n};\n\nexport async function aiListReleasesOverview(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  options?: AiListReleasesOverviewOptions,\n): Promise<string> {\n  const list = await listReleases(client, projectId);\n  const brief = list\n    .slice(0, 30)\n    .map(\n      (r) =>\n        `- ${r.tag_name}: ${r.name} (${r.released_at ?? r.created_at ?? \"\"})`,\n    )\n    .join(\"\\n\");\n\n  const user = truncateForPrompt(brief, options?.maxPromptChars ?? 40_000);\n\n  const summary = await llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nSummarize release cadence and naming patterns briefly. Markdown.`,\n    user,\n  });\n\n  if (options?.postSummaryToWikiSlug) {\n    await upsertWikiPage(client, projectId, options.postSummaryToWikiSlug, {\n      content: summary,\n      title: options.wikiPageTitle,\n      format: options.wikiFormat,\n    });\n  }\n\n  return summary;\n}\n", "import {\n  POLICY_DEFAULT,\n  POLICY_NO_SECRET_EXFILTRATION,\n} from \"../ai/policies.js\";\nimport { truncateForPrompt } from \"../ai/textLimits.js\";\nimport type { LabflowLlm } from \"../ai/types.js\";\nimport type { GitlabClient } from \"../gitlab/client.js\";\nimport {\n  compareRefs,\n  createCommitNote,\n  getFile,\n  listCommitComments,\n  listCommits,\n} from \"../gitlab/repository.js\";\n\nfunction formatCommitLine(c: {\n  id: string;\n  title?: string;\n  message?: string;\n  authored_date?: string;\n}): string {\n  const msg = c.title ?? (c.message ?? \"\").split(\"\\n\")[0] ?? \"\";\n  return `- ${c.id.slice(0, 8)} ${c.authored_date ?? \"\"} \u2014 ${msg}`;\n}\n\n/** Release-note style bullets from commits on a ref. */\nexport async function aiCommitsReleaseNoteBullets(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  ref: string,\n  options?: { model?: string; maxPromptChars?: number; path?: string },\n): Promise<string> {\n  const commits = await listCommits(client, projectId, {\n    ref_name: ref,\n    path: options?.path,\n  });\n\n  const lines = commits.map(formatCommitLine).join(\"\\n\");\n  const user = truncateForPrompt(\n    `Ref: ${ref}\\n\\nCommits:\\n${lines}`,\n    options?.maxPromptChars ?? 100_000,\n  );\n\n  return llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nWrite concise release-note bullets for end users (not every commit). Group related items. Markdown.`,\n    user,\n  });\n}\n\nexport type AiCommitCommentsDigestOptions = {\n  model?: string;\n  maxPromptChars?: number;\n  /**\n   * When true, POSTs the generated markdown as a new comment on this commit (`POST \u2026/repository/commits/:sha/comments`).\n   * Requires a token with the **`api`** scope.\n   */\n  postSummaryAsCommitNote?: boolean;\n};\n\nasync function maybePostCommitSummary(\n  client: GitlabClient,\n  projectId: string | number,\n  sha: string,\n  summary: string,\n  post: boolean | undefined,\n): Promise<void> {\n  if (!post) {\n    return;\n  }\n  await createCommitNote(client, projectId, sha, { note: summary });\n}\n\n/** Summarize discussion anchored on a commit SHA. */\nexport async function aiCommitCommentsDigest(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  sha: string,\n  options?: AiCommitCommentsDigestOptions,\n): Promise<string> {\n  const notes = await listCommitComments(client, projectId, sha);\n  const formatted = notes\n    .map(\n      (n) => `[${n.created_at ?? \"\"}] ${n.author?.username ?? \"?\"}: ${n.body}`,\n    )\n    .join(\"\\n\\n\");\n\n  const user = truncateForPrompt(formatted, options?.maxPromptChars ?? 40_000);\n\n  const summary = await llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nSummarize commit discussion / review notes briefly. Markdown.`,\n    user,\n  });\n\n  await maybePostCommitSummary(\n    client,\n    projectId,\n    sha,\n    summary,\n    options?.postSummaryAsCommitNote,\n  );\n  return summary;\n}\n\nexport type ExplainPathOptions = {\n  /** Skip calling the LLM if base64-decoded size estimate exceeds this (bytes). */\n  maxDecodedBytes?: number;\n};\n\n/**\n * Explain what a path does (redacted for size). **Do not** send likely-secret files without review.\n */\nexport async function aiExplainRepositoryPath(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  filePath: string,\n  ref: string,\n  options?: ExplainPathOptions & { model?: string; maxPromptChars?: number },\n): Promise<string> {\n  const blob = await getFile(client, projectId, filePath, ref);\n  const maxBytes = options?.maxDecodedBytes ?? 80_000;\n  let payload = `(file ${blob.file_path}, size ${blob.size} bytes, encoding ${blob.encoding ?? \"text\"})\\n`;\n\n  if (blob.encoding === \"base64\" && typeof blob.content === \"string\") {\n    const buf = Buffer.from(blob.content, \"base64\");\n    if (buf.length > maxBytes) {\n      payload += `[Skipped body: ${buf.length} bytes > maxDecodedBytes ${maxBytes}]`;\n    } else {\n      payload += buf.toString(\"utf8\");\n    }\n  } else {\n    payload += blob.content ?? \"\";\n  }\n\n  const user = truncateForPrompt(payload, options?.maxPromptChars ?? 60_000);\n\n  return llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\n${POLICY_NO_SECRET_EXFILTRATION}\\nDescribe what this path is responsible for and notable dependencies. If content looks truncated, say so. Markdown.`,\n    user,\n  });\n}\n\n/** Compare refs as a narrative (diff text optionally summarized separately via {@link summarizeCompareDiffWithSmartDiff}). */\nexport async function aiCompareRefsNarrative(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  from: string,\n  to: string,\n  options?: { model?: string; maxPromptChars?: number },\n): Promise<string> {\n  const cmp = await compareRefs(client, projectId, from, to);\n  const commits = (cmp.commits ?? []).map(formatCommitLine).join(\"\\n\");\n  const paths = (cmp.diffs ?? [])\n    .map(\n      (d) =>\n        `${d.new_path ?? d.old_path ?? \"?\"} (${d.new_file ? \"add\" : d.deleted_file ? \"del\" : \"mod\"})`,\n    )\n    .join(\"\\n\");\n  const user = truncateForPrompt(\n    `Compare ${from}..${to}\\n\\n## Commits\\n${commits}\\n\\n## Paths\\n${paths}`,\n    options?.maxPromptChars ?? 80_000,\n  );\n\n  return llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nHigh-level narrative of what changed between refs (no line-by-line diff included). Markdown.`,\n    user,\n  });\n}\n\n/** Nudge toward Conventional Commits style (advisory). */\nexport async function aiConventionalCommitNudge(\n  llm: LabflowLlm,\n  sampleCommitMessages: string[],\n  options?: { model?: string },\n): Promise<string> {\n  const user = sampleCommitMessages.join(\"\\n\\n---\\n\\n\");\n  return llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nReview these commit messages and suggest Conventional Commits improvements (type(scope): subject). Short Markdown.`,\n    user,\n  });\n}\n", "import { POLICY_DEFAULT } from \"../ai/policies.js\";\nimport { truncateForPrompt } from \"../ai/textLimits.js\";\nimport type { LabflowLlm } from \"../ai/types.js\";\nimport type { GitlabClient } from \"../gitlab/client.js\";\nimport { type SearchScope, searchInProject } from \"../gitlab/search.js\";\n\n/** Pull search results as raw JSON, then compress into an \"everything mentioning X\" briefing. */\nexport async function aiSearchMentionBundle(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  scope: SearchScope,\n  search: string,\n  options?: { model?: string; maxPromptChars?: number },\n): Promise<string> {\n  const hits = await searchInProject(client, projectId, scope, search);\n  const user = truncateForPrompt(\n    JSON.stringify({ scope, search, hits }, null, 2),\n    options?.maxPromptChars ?? 120_000,\n  );\n\n  return llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nSummarize what these GitLab search hits imply (incident timeline starter, not authoritative). Markdown.`,\n    user,\n  });\n}\n", "import { POLICY_DEFAULT, POLICY_SECURITY_FINDINGS } from \"../ai/policies.js\";\nimport { truncateForPrompt } from \"../ai/textLimits.js\";\nimport type { LabflowLlm } from \"../ai/types.js\";\nimport { listProjectAuditEvents } from \"../gitlab/audit.js\";\nimport type { GitlabClient } from \"../gitlab/client.js\";\nimport { listVulnerabilityFindings } from \"../gitlab/security.js\";\n\nexport async function aiVulnerabilityFindingsBrief(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  options?: { model?: string; maxPromptChars?: number },\n): Promise<string> {\n  const findings = await listVulnerabilityFindings(client, projectId);\n  const text = findings\n    .slice(0, 200)\n    .map(\n      (f, i) =>\n        `${i + 1}. [${f.severity ?? \"?\"}] ${f.name ?? f.report_type ?? \"finding\"} \u2014 ${f.description ?? \"\"}`,\n    )\n    .join(\"\\n\");\n\n  const user = truncateForPrompt(text, options?.maxPromptChars ?? 100_000);\n\n  return llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\n${POLICY_SECURITY_FINDINGS}\\nCluster findings, suggest triage order (not auto-fix). Markdown.`,\n    user,\n  });\n}\n\nexport async function aiAuditEventsDashboardSummary(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  options?: { model?: string; maxPromptChars?: number },\n): Promise<string> {\n  const events = await listProjectAuditEvents(client, projectId);\n  const text = events\n    .slice(0, 200)\n    .map(\n      (e, i) =>\n        `${i + 1}. ${e.created_at ?? \"\"} ${e.author?.username ?? \"?\"} \u2014 ${e.entity_type ?? \"?\"} ${JSON.stringify(e.details ?? {})}`,\n    )\n    .join(\"\\n\");\n\n  const user = truncateForPrompt(text, options?.maxPromptChars ?? 100_000);\n\n  return llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nSummarize audit activity for a compliance dashboard (patterns, anomalies to review). Markdown.`,\n    user,\n  });\n}\n", "import {\n  POLICY_DEFAULT,\n  POLICY_NO_SECRET_EXFILTRATION,\n} from \"../ai/policies.js\";\nimport { truncateForPrompt } from \"../ai/textLimits.js\";\nimport type { LabflowLlm } from \"../ai/types.js\";\nimport type { GitlabClient } from \"../gitlab/client.js\";\nimport {\n  getSnippet,\n  getWikiPage,\n  listWikiPages,\n  upsertWikiPage,\n} from \"../gitlab/wikiAndSnippets.js\";\n\n/** Optional LLM + wiki publish fields shared by wiki insight helpers. */\nexport type AiWikiInsightOptions = {\n  model?: string;\n  maxPromptChars?: number;\n  /**\n   * When set, writes the generated markdown to this wiki page slug via `upsertWikiPage` (requires API token with write access).\n   * Use a slug different from the source page if you must not overwrite the full runbook with a short TL;DR.\n   */\n  postSummaryToWikiSlug?: string;\n  wikiPageTitle?: string;\n  wikiFormat?: string;\n};\n\nexport type AiWikiRunbookTldrOptions = AiWikiInsightOptions & {\n  wikiVersion?: string;\n};\n\nasync function maybePostWikiInsight(\n  client: GitlabClient,\n  projectId: string | number,\n  slug: string | undefined,\n  summary: string,\n  title: string | undefined,\n  format: string | undefined,\n): Promise<void> {\n  if (!slug) {\n    return;\n  }\n  await upsertWikiPage(client, projectId, slug, {\n    content: summary,\n    title,\n    format,\n  });\n}\n\nexport async function aiWikiRunbookTldr(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  slug: string,\n  options?: AiWikiRunbookTldrOptions,\n): Promise<string> {\n  const page = await getWikiPage(client, projectId, slug, options?.wikiVersion);\n  const user = truncateForPrompt(\n    page.content ?? \"\",\n    options?.maxPromptChars ?? 80_000,\n  );\n\n  const summary = await llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\n${POLICY_NO_SECRET_EXFILTRATION}\\nTL;DR this runbook for on-call: steps, rollback, links to verify. Markdown.`,\n    user,\n  });\n\n  await maybePostWikiInsight(\n    client,\n    projectId,\n    options?.postSummaryToWikiSlug,\n    summary,\n    options?.wikiPageTitle,\n    options?.wikiFormat,\n  );\n  return summary;\n}\n\nexport type AiWikiOutdatedDocHintsOptions = AiWikiInsightOptions & {\n  sampleSlugs?: string[];\n};\n\n/** Heuristic doc review when given wiki index + optional sample pages. */\nexport async function aiWikiOutdatedDocHints(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  options?: AiWikiOutdatedDocHintsOptions,\n): Promise<string> {\n  const index = await listWikiPages(client, projectId);\n  const slugs = options?.sampleSlugs ?? index.slice(0, 5).map((p) => p.slug);\n  const samples: string[] = [];\n  for (const slug of slugs) {\n    const page = await getWikiPage(client, projectId, slug).catch(() => null);\n    if (page?.content) {\n      samples.push(`## ${slug}\\n${page.content.slice(0, 8000)}`);\n    }\n  }\n\n  const user = truncateForPrompt(\n    `Wiki titles:\\n${index.map((p) => `- ${p.slug}: ${p.title}`).join(\"\\n\")}\\n\\nSamples:\\n${samples.join(\"\\n\\n\")}`,\n    options?.maxPromptChars ?? 100_000,\n  );\n\n  const summary = await llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\n${POLICY_NO_SECRET_EXFILTRATION}\\nFlag likely outdated sections, conflicts, or missing runbook elements (not guaranteed). Markdown.`,\n    user,\n  });\n\n  await maybePostWikiInsight(\n    client,\n    projectId,\n    options?.postSummaryToWikiSlug,\n    summary,\n    options?.wikiPageTitle,\n    options?.wikiFormat,\n  );\n  return summary;\n}\n\nexport async function aiSnippetTldr(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  snippetId: number,\n  options?: { model?: string; maxPromptChars?: number },\n): Promise<string> {\n  const sn = await getSnippet(client, snippetId);\n  const user = truncateForPrompt(\n    `${sn.title}\\n${sn.description ?? \"\"}\\n${JSON.stringify(sn)}`,\n    options?.maxPromptChars ?? 40_000,\n  );\n\n  return llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\n${POLICY_NO_SECRET_EXFILTRATION}\\nSummarize snippet purpose and safe usage. Markdown.`,\n    user,\n  });\n}\n\nexport async function aiSuggestMergeWikiPages(\n  client: GitlabClient,\n  llm: LabflowLlm,\n  projectId: string | number,\n  options?: AiWikiInsightOptions,\n): Promise<string> {\n  const index = await listWikiPages(client, projectId);\n  const user = truncateForPrompt(\n    index.map((p) => `- ${p.slug}: ${p.title}`).join(\"\\n\"),\n    options?.maxPromptChars ?? 40_000,\n  );\n\n  const summary = await llm({\n    model: options?.model,\n    system: `${POLICY_DEFAULT}\\nSuggest pages that may overlap or should merge (outline only). Markdown.`,\n    user,\n  });\n\n  await maybePostWikiInsight(\n    client,\n    projectId,\n    options?.postSummaryToWikiSlug,\n    summary,\n    options?.wikiPageTitle,\n    options?.wikiFormat,\n  );\n  return summary;\n}\n", "import {\n  type CommitInfo,\n  DEFAULT_NOISE_EXCLUDES,\n  type DiffShapingOptions,\n  generateSummary,\n  type LlmModelProvider,\n  type LlmProviderId,\n  resolveLlmMaxDiffChars,\n  shapeUnifiedDiff,\n  truncateUnifiedDiffForLlm,\n} from \"@mcarvin/smart-diff\";\n\nimport type { GitlabClient } from \"../gitlab/client.js\";\nimport {\n  createMergeRequestNote,\n  getMergeRequest,\n  getMergeRequestChanges,\n  listMergeRequestCommits,\n} from \"../gitlab/mergeRequests.js\";\n\nimport { compareRefs } from \"../gitlab/repository.js\";\n\ntype MrDiffFile = {\n  old_path: string | null;\n  new_path: string | null;\n  diff: string;\n};\n\nexport type SummarizeGitLabMergeRequestDiffOptions = {\n  client: GitlabClient;\n  projectId: string | number;\n  mergeRequestIid: number;\n  /** Passed through to smart-diff (team line in prompt). */\n  teamName?: string;\n  /**\n   * Explicit LLM provider id (OpenAI / Anthropic / Google / Bedrock / Mistral /\n   * Cohere / Groq / xAI / DeepSeek / openai-compatible). Wins over\n   * `LLM_PROVIDER` env + auto-detection.\n   */\n  provider?: LlmProviderId;\n  model?: string;\n  maxDiffChars?: number;\n  /** Override default smart-diff system prompt. */\n  systemPrompt?: string;\n  /**\n   * Hand-wire a smart-diff `ChatModel` factory \u2014 bypasses smart-diff's\n   * env-based provider resolution (useful in tests or for custom setups).\n   */\n  llmModelProvider?: LlmModelProvider;\n  /** When true, POST the generated summary as a new merge request note (requires token with API write access). */\n  postSummaryAsMergeRequestNote?: boolean;\n  /**\n   * smart-diff v2.1+ unified-diff token-reduction controls. The GitLab\n   * `/changes` and `/compare` endpoints return a pre-rendered unified diff,\n   * so only `stripDiffPreamble` and `maxHunkLines` affect the bridge output\n   * (`contextLines` and `ignoreWhitespace` are git-arg flags and apply only\n   * to the local `summarizeGitDiff` pipeline).\n   */\n  diffShaping?: DiffShapingOptions;\n  /**\n   * Drop files whose path matches smart-diff's built-in noise list\n   * (`DEFAULT_NOISE_EXCLUDES`: lockfiles, `node_modules`, `dist`, `build`,\n   * `out`, `coverage`, `__snapshots__`). Combines with `excludeFolders`.\n   */\n  excludeDefaultNoise?: boolean;\n  /**\n   * Keep only files whose path matches one of these segments (folder name,\n   * file basename, or prefix). Empty / omitted means \"keep all\". Matching is\n   * substring-based on `/`-delimited path segments.\n   */\n  includeFolders?: string[];\n  /**\n   * Drop files whose path matches one of these segments (folder name, file\n   * basename, or prefix). Combines with `excludeDefaultNoise`.\n   */\n  excludeFolders?: string[];\n};\n\nfunction normalizePatterns(patterns: readonly string[] | undefined): string[] {\n  if (!patterns || patterns.length === 0) return [];\n  const out: string[] = [];\n  for (const raw of patterns) {\n    if (typeof raw !== \"string\") continue;\n    const trimmed = raw\n      .trim()\n      .replace(/^\\.\\//, \"\")\n      .replace(/^\\/+|\\/+$/g, \"\");\n    if (trimmed) out.push(trimmed);\n  }\n  return out;\n}\n\nfunction pathMatchesSegment(path: string, segment: string): boolean {\n  if (!path || !segment) return false;\n  if (path === segment) return true;\n  if (path.startsWith(`${segment}/`)) return true;\n  if (path.includes(`/${segment}/`)) return true;\n  const basename = path.slice(path.lastIndexOf(\"/\") + 1);\n  return basename === segment;\n}\n\nfunction pathMatchesAny(path: string, segments: string[]): boolean {\n  for (const s of segments) {\n    if (pathMatchesSegment(path, s)) return true;\n  }\n  return false;\n}\n\ntype PathFilter = {\n  includes: string[];\n  excludes: string[];\n};\n\nfunction buildPathFilter(\n  options: Pick<\n    SummarizeGitLabMergeRequestDiffOptions,\n    \"includeFolders\" | \"excludeFolders\" | \"excludeDefaultNoise\"\n  >,\n): PathFilter {\n  const includes = normalizePatterns(options.includeFolders);\n  const excludes = normalizePatterns(options.excludeFolders);\n  if (options.excludeDefaultNoise) {\n    for (const noise of DEFAULT_NOISE_EXCLUDES) {\n      if (!excludes.includes(noise)) excludes.push(noise);\n    }\n  }\n  return { includes, excludes };\n}\n\nfunction filterDiffFiles(\n  diffs: MrDiffFile[],\n  filter: PathFilter,\n): MrDiffFile[] {\n  if (filter.includes.length === 0 && filter.excludes.length === 0)\n    return diffs;\n  return diffs.filter((c) => {\n    const newPath = c.new_path ?? \"\";\n    const oldPath = c.old_path ?? \"\";\n    const candidatePaths = [newPath, oldPath].filter(\n      (p): p is string => p.length > 0,\n    );\n    if (candidatePaths.length === 0) return true;\n    if (filter.excludes.length > 0) {\n      const allExcluded = candidatePaths.every((p) =>\n        pathMatchesAny(p, filter.excludes),\n      );\n      if (allExcluded) return false;\n    }\n    if (filter.includes.length > 0) {\n      const anyIncluded = candidatePaths.some((p) =>\n        pathMatchesAny(p, filter.includes),\n      );\n      if (!anyIncluded) return false;\n    }\n    return true;\n  });\n}\n\nfunction buildUnifiedDiffFromMrChanges(diffs: MrDiffFile[]): {\n  diffText: string;\n  fileNames: string[];\n} {\n  const fileNames: string[] = [];\n  const parts: string[] = [];\n\n  for (const c of diffs) {\n    const name = c.new_path ?? c.old_path ?? \"unknown\";\n    fileNames.push(name);\n    parts.push(\n      `diff --git a/${c.old_path ?? \"/dev/null\"} b/${c.new_path ?? \"/dev/null\"}\\n${c.diff}`,\n    );\n  }\n\n  return { diffText: parts.join(\"\\n\"), fileNames };\n}\n\n/**\n * Summarize a merge request diff using `@mcarvin/smart-diff` (same pipeline as local `git diff`,\n * but fed from GitLab `/merge_requests/:iid/changes`). Enriches with MR title/branches in flags.\n */\nexport async function summarizeMergeRequestDiffWithSmartDiff(\n  options: SummarizeGitLabMergeRequestDiffOptions,\n): Promise<string> {\n  const mr = await getMergeRequest(\n    options.client,\n    options.projectId,\n    options.mergeRequestIid,\n  );\n  const [changes, commits] = await Promise.all([\n    getMergeRequestChanges(\n      options.client,\n      options.projectId,\n      options.mergeRequestIid,\n    ),\n    listMergeRequestCommits(\n      options.client,\n      options.projectId,\n      options.mergeRequestIid,\n    ),\n  ]);\n\n  const filter = buildPathFilter(options);\n  const filteredChanges = filterDiffFiles(changes.changes ?? [], filter);\n  const { diffText: rawDiff, fileNames } =\n    buildUnifiedDiffFromMrChanges(filteredChanges);\n\n  const commitInfos: CommitInfo[] = commits.map((c) => ({\n    hash: c.id,\n    message: c.message ?? c.title ?? \"\",\n  }));\n\n  const shaped = shapeUnifiedDiff(rawDiff, options.diffShaping);\n  const max = resolveLlmMaxDiffChars(options.maxDiffChars);\n  const diffText = truncateUnifiedDiffForLlm(shaped, max);\n\n  const from = mr.target_branch ?? \"target\";\n  const to = mr.source_branch ?? \"source\";\n\n  const summary = await generateSummary({\n    diffText,\n    fileNames,\n    commits: commitInfos,\n    flags: {\n      from,\n      to,\n      team: options.teamName,\n      model: options.model,\n      provider: options.provider,\n      maxDiffChars: options.maxDiffChars,\n      systemPrompt: options.systemPrompt,\n    },\n    llmModelProvider: options.llmModelProvider,\n  });\n\n  if (options.postSummaryAsMergeRequestNote) {\n    await createMergeRequestNote(\n      options.client,\n      options.projectId,\n      options.mergeRequestIid,\n      {\n        body: summary,\n      },\n    );\n  }\n\n  return summary;\n}\n\nexport type SummarizeCompareDiffOptions = {\n  client: GitlabClient;\n  projectId: string | number;\n  from: string;\n  to: string;\n  teamName?: string;\n  provider?: LlmProviderId;\n  model?: string;\n  maxDiffChars?: number;\n  systemPrompt?: string;\n  llmModelProvider?: LlmModelProvider;\n  /** See {@link SummarizeGitLabMergeRequestDiffOptions.diffShaping}. */\n  diffShaping?: DiffShapingOptions;\n  /** See {@link SummarizeGitLabMergeRequestDiffOptions.excludeDefaultNoise}. */\n  excludeDefaultNoise?: boolean;\n  /** See {@link SummarizeGitLabMergeRequestDiffOptions.includeFolders}. */\n  includeFolders?: string[];\n  /** See {@link SummarizeGitLabMergeRequestDiffOptions.excludeFolders}. */\n  excludeFolders?: string[];\n};\n\n/** Like {@link summarizeMergeRequestDiffWithSmartDiff}, but for `/repository/compare`. */\nexport async function summarizeCompareDiffWithSmartDiff(\n  options: SummarizeCompareDiffOptions,\n): Promise<string> {\n  const cmp = await compareRefs(\n    options.client,\n    options.projectId,\n    options.from,\n    options.to,\n  );\n  const filter = buildPathFilter(options);\n  const diffs = filterDiffFiles(cmp.diffs ?? [], filter);\n  const { diffText: rawDiff, fileNames } = buildUnifiedDiffFromMrChanges(diffs);\n  const commitInfos: CommitInfo[] = (cmp.commits ?? []).map((c) => ({\n    hash: c.id,\n    message: c.message ?? c.title ?? \"\",\n  }));\n\n  const shaped = shapeUnifiedDiff(rawDiff, options.diffShaping);\n  const max = resolveLlmMaxDiffChars(options.maxDiffChars);\n  const diffText = truncateUnifiedDiffForLlm(shaped, max);\n\n  return generateSummary({\n    diffText,\n    fileNames,\n    commits: commitInfos,\n    flags: {\n      from: options.from,\n      to: options.to,\n      team: options.teamName,\n      model: options.model,\n      provider: options.provider,\n      maxDiffChars: options.maxDiffChars,\n      systemPrompt: options.systemPrompt,\n    },\n    llmModelProvider: options.llmModelProvider,\n  });\n}\n"],
  "mappings": "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",
  "names": ["createGitClient", "DEFAULT_GIT_DIFF_SYSTEM_PROMPT", "DEFAULT_NOISE_EXCLUDES", "defaultModelForProvider", "detectLlmProvider", "filterCommitsByMessageRegexes", "generateSummary", "getChangedFiles", "getCommits", "getDiff", "getDiffSummary", "getRepoRoot", "isLlmProviderConfigured", "LLM_GATEWAY_REQUIRED_MESSAGE", "parseLlmDefaultHeadersFromEnv", "resolveLanguageModel", "resolveLlmBaseUrl", "resolveLlmMaxDiffChars", "shapeUnifiedDiff", "summarizeGitDiff", "truncateUnifiedDiffForLlm", "isLlmProviderConfigured", "LLM_GATEWAY_REQUIRED_MESSAGE", "resolveLanguageModel", "POLICY_NO_SECRET_EXFILTRATION", "POLICY_SECURITY_FINDINGS", "POLICY_HUMAN_REVIEW", "POLICY_DEFAULT", "truncateForPrompt", "text", "maxChars", "createLabflowLlm", "options", "maxUserChars", "envModel", "defaultModel", "resolveModel", "modelId", "isLlmProviderConfigured", "LLM_GATEWAY_REQUIRED_MESSAGE", "resolveLanguageModel", "input", "user", "truncateForPrompt", "system", "POLICY_DEFAULT", "model", "text", "resolveTemperature", "resolveMaxOutputTokens", "raw", "parsed", "encodeProjectId", "projectId", "encodeGroupId", "groupId", "listProjectAuditEvents", "client", "projectId", "query", "id", "encodeProjectId", "GitlabHttpError", "message", "init", "encodeQuery", "params", "pairs", "k", "v", "normalizeBaseUrl", "raw", "trimmed", "GitlabClient", "options", "method", "path", "init", "q", "encodeQuery", "url", "res", "text", "GitlabHttpError", "query", "maxPages", "perPage", "out", "page", "chunk", "listDeployments", "client", "projectId", "query", "id", "encodeProjectId", "listEnvironments", "getEpic", "client", "groupId", "epicIid", "gid", "encodeGroupId", "listEpicIssues", "listGroupEpics", "query", "listProjectEvents", "client", "projectId", "query", "id", "encodeProjectId", "listGroupEvents", "groupId", "gid", "encodeGroupId", "getIssue", "client", "projectId", "issueIid", "id", "encodeProjectId", "listIssueNotes", "createIssueNote", "params", "listProjectIssues", "query", "getMergeRequest", "client", "projectId", "mergeRequestIid", "id", "encodeProjectId", "listMergeRequestNotes", "createMergeRequestNote", "params", "getMergeRequestChanges", "listMergeRequestCommits", "listMergeRequestDiscussions", "listPipelines", "client", "projectId", "query", "id", "encodeProjectId", "getPipeline", "pipelineId", "listPipelineJobs", "getJob", "jobId", "getJobTrace", "listCommits", "client", "projectId", "query", "id", "encodeProjectId", "listCommitComments", "sha", "createCommitNote", "params", "shaSeg", "getFile", "filePath", "ref", "compareRefs", "from", "to", "getProject", "client", "projectId", "id", "encodeProjectId", "getReadmeFile", "filePath", "ref", "getFile", "getReleaseByTag", "client", "projectId", "tagName", "id", "encodeProjectId", "listReleases", "upsertRelease", "params", "pathTag", "existing", "e", "GitlabHttpError", "searchGitlab", "client", "options", "query", "searchInProject", "projectId", "scope", "search", "searchInGroup", "groupId", "listVulnerabilityFindings", "client", "projectId", "query", "id", "encodeProjectId", "listWikiPages", "client", "projectId", "id", "encodeProjectId", "getWikiPage", "slug", "version", "path", "createWikiPage", "params", "updateWikiPage", "body", "upsertWikiPage", "existing", "e", "GitlabHttpError", "listProjectSnippets", "getSnippet", "snippetId", "formatEvent", "aiProjectWeeklyDigest", "client", "llm", "projectId", "options", "raw", "listProjectEvents", "user", "truncateForPrompt", "POLICY_DEFAULT", "aiGroupWeeklyDigest", "groupId", "listGroupEvents", "aiPostDeployIncidentBrief", "client", "llm", "projectId", "options", "deps", "listDeployments", "envs", "listEnvironments", "block", "d", "e", "user", "truncateForPrompt", "POLICY_DEFAULT", "aiEpicRoadmapRollup", "client", "llm", "groupId", "epicIid", "options", "epic", "getEpic", "issues", "listEpicIssues", "head", "issueLines", "i", "user", "truncateForPrompt", "POLICY_DEFAULT", "formatIssueHeader", "issue", "labels", "l", "formatNote", "n", "who", "maybePostIssueSummary", "client", "projectId", "issueIid", "summary", "post", "createIssueNote", "aiIssueThreadSummary", "llm", "options", "getIssue", "notes", "listIssueNotes", "user", "truncateForPrompt", "POLICY_DEFAULT", "aiStaleIssueSummary", "aiIssueSuggestedNextStep", "listOpenIssuesForProject", "state", "listProjectIssues", "formatNote", "n", "who", "formatMrHeader", "mr", "labels", "l", "assignees", "a", "maybePostMergeRequestSummary", "client", "projectId", "mergeRequestIid", "summary", "post", "createMergeRequestNote", "aiMergeRequestDiscussionDigest", "llm", "options", "getMergeRequest", "notes", "discussions", "listMergeRequestNotes", "listMergeRequestDiscussions", "notesBlock", "discBlock", "d", "i", "thread", "raw", "user", "truncateForPrompt", "POLICY_DEFAULT", "aiWhatChangedSinceLastReview", "since", "cut", "filtered", "aiSuggestedMergeRequestReply", "context", "tail", "aiMergeRequestActionItems", "discText", "aiMergeRequestReviewerBriefingMeta", "jobNeedsFailureAnalysis", "status", "formatJobHeader", "j", "url", "fr", "aiPipelineJobLogSummary", "client", "llm", "projectId", "jobId", "options", "job", "getJob", "trace", "getJobTrace", "perJobCap", "logBlock", "truncateForPrompt", "user", "prompt", "POLICY_DEFAULT", "POLICY_NO_SECRET_EXFILTRATION", "aiPipelineRunSummary", "pipelineId", "pipeline", "getPipeline", "jobs", "listPipelineJobs", "failedOnly", "lines", "x", "traceSections", "snippet", "aiProjectReadmeConsistency", "client", "llm", "projectId", "options", "project", "getProject", "ref", "readmePath", "readmeBody", "blob", "getReadmeFile", "meta", "user", "truncateForPrompt", "POLICY_DEFAULT", "POLICY_NO_SECRET_EXFILTRATION", "aiDraftReleaseNotes", "client", "llm", "projectId", "tagName", "options", "release", "getReleaseByTag", "prior", "commitText", "compareRefs", "c", "listCommits", "relDesc", "user", "truncateForPrompt", "summary", "POLICY_DEFAULT", "upsertRelease", "aiListReleasesOverview", "brief", "listReleases", "r", "upsertWikiPage", "formatCommitLine", "c", "msg", "aiCommitsReleaseNoteBullets", "client", "llm", "projectId", "ref", "options", "lines", "listCommits", "user", "truncateForPrompt", "POLICY_DEFAULT", "maybePostCommitSummary", "sha", "summary", "post", "createCommitNote", "aiCommitCommentsDigest", "formatted", "listCommitComments", "n", "aiExplainRepositoryPath", "filePath", "blob", "getFile", "maxBytes", "payload", "buf", "POLICY_NO_SECRET_EXFILTRATION", "aiCompareRefsNarrative", "from", "to", "cmp", "compareRefs", "commits", "paths", "d", "aiConventionalCommitNudge", "sampleCommitMessages", "aiSearchMentionBundle", "client", "llm", "projectId", "scope", "search", "options", "hits", "searchInProject", "user", "truncateForPrompt", "POLICY_DEFAULT", "aiVulnerabilityFindingsBrief", "client", "llm", "projectId", "options", "text", "listVulnerabilityFindings", "f", "i", "user", "truncateForPrompt", "POLICY_DEFAULT", "POLICY_SECURITY_FINDINGS", "aiAuditEventsDashboardSummary", "listProjectAuditEvents", "e", "maybePostWikiInsight", "client", "projectId", "slug", "summary", "title", "format", "upsertWikiPage", "aiWikiRunbookTldr", "llm", "options", "page", "getWikiPage", "user", "truncateForPrompt", "POLICY_DEFAULT", "POLICY_NO_SECRET_EXFILTRATION", "aiWikiOutdatedDocHints", "index", "listWikiPages", "slugs", "p", "samples", "aiSnippetTldr", "snippetId", "sn", "getSnippet", "aiSuggestMergeWikiPages", "DEFAULT_NOISE_EXCLUDES", "generateSummary", "resolveLlmMaxDiffChars", "shapeUnifiedDiff", "truncateUnifiedDiffForLlm", "normalizePatterns", "patterns", "out", "raw", "trimmed", "pathMatchesSegment", "path", "segment", "pathMatchesAny", "segments", "s", "buildPathFilter", "options", "includes", "excludes", "noise", "DEFAULT_NOISE_EXCLUDES", "filterDiffFiles", "diffs", "filter", "c", "newPath", "oldPath", "candidatePaths", "p", "buildUnifiedDiffFromMrChanges", "fileNames", "parts", "name", "summarizeMergeRequestDiffWithSmartDiff", "mr", "getMergeRequest", "changes", "commits", "getMergeRequestChanges", "listMergeRequestCommits", "filteredChanges", "rawDiff", "commitInfos", "shaped", "shapeUnifiedDiff", "max", "resolveLlmMaxDiffChars", "diffText", "truncateUnifiedDiffForLlm", "from", "to", "summary", "generateSummary", "createMergeRequestNote", "summarizeCompareDiffWithSmartDiff", "cmp", "compareRefs"]
}
