import { clampInt, cursorApi, trimString } from './lib/client.ts'
export type ListWorkersParams = {
status?: 'all' | 'in_use' | 'idle'
limit?: number
nextPageToken?: string
}
/**
* List self-hosted pool workers (requires pool service account key).
*
* @param params.status - Filter by `all`, `in_use`, or `idle`.
* @param params.limit - Page size (1–100); default 50.
* @returns Worker list and optional pagination token.
* @example
* import { listWorkers } from 'kody:@kentcdodds/cursor/workers'
* const workers = await listWorkers({ status: 'idle', limit: 50 })
* // => { workers: [...], nextPageToken: '...' }
*/
export async function listWorkers(params: ListWorkersParams = {}) {
const query: Record<string, string | number> = {}
if (params.status) query.status = params.status
if (params.limit !== undefined) {
query.limit = clampInt(params.limit, 1, 100, 50)
}
if (params.nextPageToken) query.nextPageToken = params.nextPageToken
return cursorApi({
path: '/v0/private-workers',
query,
})
}
/**
* Return connected and in-use worker counts for fleet autoscaling.
*
* @returns User and team worker utilization summary.
* @example
* import { getFleetSummary } from 'kody:@kentcdodds/cursor/workers'
* const summary = await getFleetSummary()
* // => { teamSummary: { totalConnected: 10, inUse: 8 } }
*/
export async function getFleetSummary() {
return cursorApi({ path: '/v0/private-workers/summary' })
}
/**
* Retrieve a single self-hosted pool worker by id.
*
* @param params.id - Worker id (e.g. `pw_123`).
* @returns Worker details.
* @example
* import { getWorker } from 'kody:@kentcdodds/cursor/workers'
* const worker = await getWorker({ id: 'pw_123' })
* // => { id: 'pw_123', status: 'idle' }
*/
export async function getWorker(params: { id: string }) {
const id = trimString(params.id)
if (!id) throw new Error('id is required')
return cursorApi({ path: `/v0/private-workers/${id}` })
}
export type ListPendingPoolRequestsParams = {
limit?: number
pageToken?: string
repository?: string
}
/**
* List pending pool requests not yet assigned to a worker.
*
* @param params.limit - Page size; default 50.
* @param params.repository - Required for repo-scoped service account keys.
* @returns Pending requests and pagination token.
* @example
* import { listPendingPoolRequests } from 'kody:@kentcdodds/cursor/workers'
* const pending = await listPendingPoolRequests({ limit: 50 })
* // => { requests: [...], nextPageToken: '...' }
*/
export async function listPendingPoolRequests(
params: ListPendingPoolRequestsParams = {},
) {
const query: Record<string, string | number> = {}
if (params.limit !== undefined) {
query.limit = clampInt(params.limit, 1, 100, 50)
}
if (params.pageToken) query.pageToken = params.pageToken
if (params.repository) query.repository = params.repository
return cursorApi({
path: '/v0/private-workers/pending-requests',
query,
})
}
export type CreateWorkerTokenParams = {
forUserEmail?: string
forUserId?: number
}
/**
* Create a one-hour user-scoped worker token (service account key required).
*
* @param params.forUserEmail - Target team member email.
* @param params.forUserId - Target team member user id (alternative to email).
* @returns Short-lived access token and expiry.
* @example
* import { createWorkerToken } from 'kody:@kentcdodds/cursor/workers'
* const token = await createWorkerToken({ forUserEmail: 'alice@company.com' })
* // => { accessToken: 'eyJ...', expiresAt: '...' }
*/
export async function createWorkerToken(params: CreateWorkerTokenParams) {
const email = trimString(params.forUserEmail)
const userId = params.forUserId
if (!email && userId === undefined) {
throw new Error('Provide forUserEmail or forUserId')
}
const body: Record<string, unknown> = {}
if (email) body.forUserEmail = email
if (userId !== undefined) body.forUserId = userId
return cursorApi({
method: 'POST',
path: '/v1/sub-tokens',
body,
})
}
/** Default export: fleet utilization summary. */
export default getFleetSummary