## Summary Behavior-preserving package code organization (wave 12), continuing after wave 11 (#2333). - **Dashboard client API peels** from `app/api/legacy.ts` into focused modules with stable re-exports: - `git.ts` — remotes, PR management, terminal sessions, git management (`withRepoPath` preserved) - `workspace-files.ts` — file browser + workspace file ops - `provider-status.ts` — auth/CLI and runtime provider status - `github-import.ts` / `gitlab-import.ts` — issue/PR import clients - `run-audit.ts` — run-audit, timeline, org tree, task review - `task-diff.ts` — task diffs and commit associations - `agent-import-generation.ts` — agent import catalog + generation - **Core types peels** from `types.ts`: - `types/run-audit.ts` - `types/planner-intervention.ts` - **Domain rename**: `task-store/remaining-ops-5.ts` → `task-store/task-id-integrity.ts` (call sites updated) - **Line-count ratchet**: `legacy.ts` ceiling ~5665 → ~3339; baseline refreshed No intentional behavior changes; public import paths via `app/api` / `@fusion/core` remain stable. ## Test plan - [x] `@fusion/core` typecheck - [x] Dashboard `tsconfig.app` typecheck (wave12-related errors cleared; pre-existing playwright/plugin env noise unchanged vs main) - [x] ESLint on peeled API modules - [x] `pnpm check:line-count` (baseline updated) - [ ] CI: Lint / Typecheck / Build / Gate <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added dashboard client support for Git remotes/PR workflows, GitHub/GitLab importing, terminals (HTTP/SSE) and PTY sessions, workspace file browsing/editing/search, and task diff viewing with file/ZIP download helpers. - Added new dashboard APIs for planning/onboarding streaming, mission interview flows, provider/auth status, dev server sessions, run-audit/timelines & task review, agent import/generation, and AI title summarization. - Added backup and settings export/import helpers, plus model discovery/usage reporting and task steering actions. - **Refactor** - Modularized dashboard API clients into focused modules while preserving the existing integration style. - **Tests** - Updated a backend-mode SQLite guidance regression test to exercise the intended implementations. - **Chores** - Refreshed internal line-count baselines. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
205 lines
7.5 KiB
TypeScript
205 lines
7.5 KiB
TypeScript
/**
|
|
* FNXC:CodeOrganization 2026-07-20-10:00:
|
|
* GitHub issue/PR import client API peeled from legacy.ts.
|
|
*/
|
|
|
|
import type { Task } from "@fusion/core";
|
|
import { api } from "./client.js";
|
|
import { withProjectId } from "./health.js";
|
|
|
|
// --- GitHub Import API ---
|
|
|
|
/** GitHub issue returned by the fetch endpoint */
|
|
/*
|
|
FNXC:GitHubImport 2026-06-22-18:30:
|
|
The Import Tasks preview pane renders the FULL issue (full body + metadata), so the list response carries the complete body plus author/state.
|
|
The GitHub issue-list endpoint already returns the full (untruncated) `body`; no per-item detail fetch is needed. `author`/`state` are surfaced for the preview metadata row.
|
|
*/
|
|
export interface GitHubIssue {
|
|
number: number;
|
|
title: string;
|
|
body: string | null;
|
|
html_url: string;
|
|
labels: Array<{ name: string }>;
|
|
state?: "open" | "closed";
|
|
author?: string | null;
|
|
}
|
|
|
|
/** Fetch open GitHub issues from a repository */
|
|
export function apiFetchGitHubIssues(
|
|
owner: string,
|
|
repo: string,
|
|
limit?: number,
|
|
labels?: string[]
|
|
): Promise<GitHubIssue[]> {
|
|
return api<GitHubIssue[]>("/github/issues/fetch", {
|
|
method: "POST",
|
|
body: JSON.stringify({ owner, repo, limit, labels }),
|
|
});
|
|
}
|
|
|
|
/** Import a specific GitHub issue as a fn task */
|
|
/*
|
|
FNXC:GitHubImportTranslate 2026-07-15-14:10:
|
|
`targetLocale` forwards the panel's ACTIVE locale so an imported task carries the same translation the operator previewed.
|
|
The server also falls back to the global `language` setting, so this argument is not load-bearing for the common case — it exists for the one case the server cannot know: a surface whose locale was browser-detected while global `language` is unset (PR #2141 review, P1).
|
|
*/
|
|
export function apiImportGitHubIssue(owner: string, repo: string, issueNumber: number, projectId?: string, targetLocale?: string): Promise<Task> {
|
|
return api<Task>(withProjectId("/github/issues/import", projectId), {
|
|
method: "POST",
|
|
body: JSON.stringify({ owner, repo, issueNumber, ...(targetLocale ? { targetLocale } : {}) }),
|
|
});
|
|
}
|
|
|
|
/** Result of a batch import operation for a single issue */
|
|
export interface BatchImportResult {
|
|
issueNumber: number;
|
|
success: boolean;
|
|
taskId?: string;
|
|
error?: string;
|
|
skipped?: boolean;
|
|
retryAfter?: number;
|
|
}
|
|
|
|
/** Batch import multiple GitHub issues as fn tasks with throttling */
|
|
export function apiBatchImportGitHubIssues(
|
|
owner: string,
|
|
repo: string,
|
|
issueNumbers: number[],
|
|
delayMs?: number,
|
|
projectId?: string,
|
|
/** See apiImportGitHubIssue: batch import must carry translations identically. */
|
|
targetLocale?: string,
|
|
): Promise<{ results: BatchImportResult[] }> {
|
|
return api<{ results: BatchImportResult[] }>(withProjectId("/github/issues/batch-import", projectId), {
|
|
method: "POST",
|
|
body: JSON.stringify({ owner, repo, issueNumbers, delayMs, ...(targetLocale ? { targetLocale } : {}) }),
|
|
});
|
|
}
|
|
|
|
// --- GitHub Pull Request Import API ---
|
|
|
|
/*
|
|
FNXC:GitHubImport 2026-06-22-18:30:
|
|
The PR-list endpoint already returns the full (untruncated) `body`; the import preview renders it in full with no per-item detail fetch. `state`/`author` surface PR metadata in the preview.
|
|
*/
|
|
export interface GitHubPull {
|
|
number: number;
|
|
title: string;
|
|
body: string | null;
|
|
html_url: string;
|
|
headBranch: string;
|
|
baseBranch: string;
|
|
state?: "open" | "closed" | "merged";
|
|
author?: string | null;
|
|
}
|
|
|
|
/** Fetch open GitHub pull requests from a repository */
|
|
export function apiFetchGitHubPulls(
|
|
owner: string,
|
|
repo: string,
|
|
limit?: number
|
|
): Promise<GitHubPull[]> {
|
|
return api<GitHubPull[]>("/github/pulls/fetch", {
|
|
method: "POST",
|
|
body: JSON.stringify({ owner, repo, limit }),
|
|
});
|
|
}
|
|
|
|
/*
|
|
FNXC:GitHubImport 2026-06-23-01:00:
|
|
Per-PR detail for the Import Tasks PR preview pane. `gh pr list` (apiFetchGitHubPulls) returns only comment COUNT + no per-check status, so the preview fetches the FULL comment thread + per-check status ON SELECTION via this client fn (never for the whole list — too expensive).
|
|
`status` is the gh CheckRun status (queued/in_progress/completed) or StatusContext state; `conclusion` (success/failure/neutral/...) is present once a check completes.
|
|
*/
|
|
/*
|
|
FNXC:GitHubImport 2026-06-23-03:30:
|
|
Comment shape carries `authorAvatarUrl?` (optional, backward-compatible) and `authorIsBot` so the preview renders an avatar + human/bot badge per comment. `authorIsBot` is derived server-side (author type is a GitHub Bot OR login ends in `[bot]`); `authorAvatarUrl` is omitted for bots whose synthetic login does not resolve to a real avatar.
|
|
*/
|
|
export interface GitHubCommentDetail {
|
|
author: string;
|
|
body: string;
|
|
createdAt: string;
|
|
authorAvatarUrl?: string;
|
|
authorIsBot: boolean;
|
|
}
|
|
|
|
export interface GitHubPullDetail {
|
|
comments: GitHubCommentDetail[];
|
|
checks: Array<{ name: string; status: string; conclusion?: string; detailsUrl?: string }>;
|
|
}
|
|
|
|
/** Fetch the full comment thread + per-check status for a single GitHub PR (called on selection in the import preview). */
|
|
export function apiFetchGitHubPullDetail(repo: string, number: number): Promise<GitHubPullDetail> {
|
|
return api<GitHubPullDetail>("/github/pulls/detail", {
|
|
method: "POST",
|
|
body: JSON.stringify({ repo, number }),
|
|
});
|
|
}
|
|
|
|
/*
|
|
FNXC:GitHubImport 2026-06-23-03:15:
|
|
Per-issue detail for the Import Tasks issue preview pane. Mirrors apiFetchGitHubPullDetail: `gh issue list` has no comment thread, so the preview fetches the FULL comment thread ON SELECTION (never for the whole list).
|
|
Issues have no checks rollup, so only `comments` is returned.
|
|
*/
|
|
export interface GitHubIssueDetail {
|
|
comments: GitHubCommentDetail[];
|
|
}
|
|
|
|
/** Fetch the full comment thread for a single GitHub issue (called on selection in the import preview). */
|
|
export function apiFetchGitHubIssueDetail(repo: string, number: number): Promise<GitHubIssueDetail> {
|
|
return api<GitHubIssueDetail>("/github/issues/detail", {
|
|
method: "POST",
|
|
body: JSON.stringify({ repo, number }),
|
|
});
|
|
}
|
|
|
|
/** Close a GitHub issue (Close issue button in the import preview). */
|
|
export async function apiCloseGitHubIssue(repo: string, number: number): Promise<void> {
|
|
await api<{ ok: boolean }>("/github/issues/close", {
|
|
method: "POST",
|
|
body: JSON.stringify({ repo, number }),
|
|
});
|
|
}
|
|
|
|
|
|
/*
|
|
FNXC:GitHubImport 2026-07-17-12:00:
|
|
Posts a new comment to the upstream GitHub issue. This is deliberately separate from
|
|
apiImportGitHubComment, which creates a Fusion resolve-feedback task from an existing comment.
|
|
*/
|
|
export async function apiAddGitHubIssueComment(repo: string, number: number, body: string): Promise<void> {
|
|
await api<{ ok: boolean }>("/github/issues/comment", {
|
|
method: "POST",
|
|
body: JSON.stringify({ repo, number, body }),
|
|
});
|
|
}
|
|
|
|
/** Import a specific GitHub pull request as a fn review task */
|
|
export function apiImportGitHubPull(owner: string, repo: string, prNumber: number, projectId?: string): Promise<Task> {
|
|
return api<Task>(withProjectId("/github/pulls/import", projectId), {
|
|
method: "POST",
|
|
body: JSON.stringify({ owner, repo, prNumber }),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* FNXC:GitHubImport 2026-07-16-18:05:
|
|
* Comment imports preserve the comment payload and issue/PR source context so the server can create a separately auditable resolve-feedback task without closing the detail window.
|
|
*/
|
|
export function apiImportGitHubComment(
|
|
params: {
|
|
owner: string;
|
|
repo: string;
|
|
number: number;
|
|
type: "issue" | "pull";
|
|
comment: Pick<GitHubCommentDetail, "author" | "body" | "createdAt">;
|
|
},
|
|
projectId?: string,
|
|
): Promise<Task> {
|
|
return api<Task>(withProjectId("/github/comments/import", projectId), {
|
|
method: "POST",
|
|
body: JSON.stringify(params),
|
|
});
|
|
}
|
|
|