feat: add CLI session sharing functionality

- Implemented share token creation and revocation for CLI sessions.
- Added a new page for viewing shared CLI sessions with SSE support.
- Introduced hooks for fetching and managing CLI session shares.
- Enhanced the IssueTerminalTab component to handle share tokens and display active shares.
- Updated API routes to support fetching and revoking share tokens.
- Added unit tests for the CLI session share manager and rate limiter.
- Updated localization files to include new strings for sharing functionality.
This commit is contained in:
catlog22
2026-02-09 22:57:05 +08:00
parent 362f354f1c
commit d0cdee2e68
18 changed files with 748 additions and 23 deletions

View File

@@ -842,6 +842,13 @@ export async function fetchQueueHistory(projectPath: string): Promise<QueueHisto
return fetchApi<QueueHistoryIndex>(`/api/queue/history?path=${encodeURIComponent(projectPath)}`);
}
/**
* Fetch a specific queue by ID
*/
export async function fetchQueueById(queueId: string, projectPath: string): Promise<IssueQueue> {
return fetchApi<IssueQueue>(`/api/queue/${encodeURIComponent(queueId)}?path=${encodeURIComponent(projectPath)}`);
}
/**
* Activate a queue
*/
@@ -5797,3 +5804,23 @@ export async function createCliSessionShareToken(
{ method: 'POST', body: JSON.stringify(input) }
);
}
export async function fetchCliSessionShares(
sessionKey: string,
projectPath?: string
): Promise<{ shares: Array<{ shareToken: string; expiresAt: string; mode: 'read' | 'write' }> }> {
return fetchApi<{ shares: Array<{ shareToken: string; expiresAt: string; mode: 'read' | 'write' }> }>(
withPath(`/api/cli-sessions/${encodeURIComponent(sessionKey)}/shares`, projectPath)
);
}
export async function revokeCliSessionShareToken(
sessionKey: string,
input: { shareToken: string },
projectPath?: string
): Promise<{ success: boolean; revoked: boolean }> {
return fetchApi<{ success: boolean; revoked: boolean }>(
withPath(`/api/cli-sessions/${encodeURIComponent(sessionKey)}/share/revoke`, projectPath),
{ method: 'POST', body: JSON.stringify(input) }
);
}

View File

@@ -35,6 +35,8 @@ export const workspaceQueryKeys = {
issuesList: (projectPath: string) => [...workspaceQueryKeys.issues(projectPath), 'list'] as const,
issuesHistory: (projectPath: string) => [...workspaceQueryKeys.issues(projectPath), 'history'] as const,
issueQueue: (projectPath: string) => [...workspaceQueryKeys.issues(projectPath), 'queue'] as const,
issueQueueById: (projectPath: string, queueId: string) =>
[...workspaceQueryKeys.issues(projectPath), 'queueById', queueId] as const,
issueQueueHistory: (projectPath: string) => [...workspaceQueryKeys.issues(projectPath), 'queueHistory'] as const,
// ========== Discoveries ==========