@rallycry/conveyor-mcp 4.2.2 → 4.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -182,6 +182,21 @@ var ConveyorConnection = class {
182
182
  ...rest
183
183
  });
184
184
  }
185
+ /** Guarded status transition used by the review tools (approve/request). */
186
+ transitionTaskStatus(params) {
187
+ const { projectId, ...rest } = params;
188
+ return this.call("transitionProjectTaskStatus", {
189
+ projectId: this.resolveProjectId(projectId),
190
+ ...rest
191
+ });
192
+ }
193
+ moveCard(params) {
194
+ const { projectId, ...rest } = params;
195
+ return this.call("moveProjectCard", {
196
+ projectId: this.resolveProjectId(projectId),
197
+ ...rest
198
+ });
199
+ }
185
200
  // ── Reviewers & Members ─────────────────────────────────────────────
186
201
  addReviewer(params) {
187
202
  const { projectId, ...rest } = params;
@@ -296,7 +311,7 @@ var ConveyorConnection = class {
296
311
  });
297
312
  }
298
313
  // ── Review Flow ─────────────────────────────────────────────────────
299
- async approveTask(taskId, projectId) {
314
+ async approveTask(taskId, projectId, risk) {
300
315
  const targetProjectId = this.resolveProjectId(projectId);
301
316
  const task = await this.call("getProjectTask", {
302
317
  projectId: targetProjectId,
@@ -304,17 +319,30 @@ var ConveyorConnection = class {
304
319
  });
305
320
  if (!task) throw new Error("Task not found");
306
321
  const nextStatus = task.status === "ReviewPR" ? "ReviewDev" : "Complete";
307
- const result = await this.updateTask({
322
+ const result = await this.transitionTaskStatus({
308
323
  projectId: targetProjectId,
309
324
  taskId,
310
- status: nextStatus
325
+ toStatus: nextStatus,
326
+ expectedFromStatus: task.status,
327
+ risk: risk ?? "low"
311
328
  });
312
329
  return { status: result.status };
313
330
  }
314
- async requestChanges(taskId, feedback, projectId) {
331
+ async requestChanges(taskId, feedback, projectId, risk) {
315
332
  const targetProjectId = this.resolveProjectId(projectId);
333
+ const task = await this.call("getProjectTask", {
334
+ projectId: targetProjectId,
335
+ taskId
336
+ });
337
+ if (!task) throw new Error("Task not found");
316
338
  await this.postToTaskChat(taskId, feedback, targetProjectId);
317
- await this.updateTask({ projectId: targetProjectId, taskId, status: "InProgress" });
339
+ await this.transitionTaskStatus({
340
+ projectId: targetProjectId,
341
+ taskId,
342
+ toStatus: "InProgress",
343
+ expectedFromStatus: task.status,
344
+ risk: risk ?? "medium"
345
+ });
318
346
  }
319
347
  approveAndMergePR(childTaskId, projectId) {
320
348
  return this.call("approveProjectMergePR", {
@@ -532,4 +560,4 @@ var ConveyorConnection = class {
532
560
  export {
533
561
  ConveyorConnection
534
562
  };
535
- //# sourceMappingURL=chunk-3HM7WTJR.js.map
563
+ //# sourceMappingURL=chunk-HRIOQERY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/connection.ts"],"sourcesContent":["/* oxlint-disable max-lines -- central MCP socket client; split after service-call helpers are extracted */\nimport { io, type Socket } from \"socket.io-client\";\n\nexport interface ConveyorMcpConfig {\n apiUrl: string;\n projectToken: string;\n projectId?: string;\n}\n\n/**\n * Canonical risk levels — kept in lockstep with `RISK_LEVELS` in\n * `@project/shared` (conveyor-mcp is published standalone and does not depend on\n * the shared package, so the vocabulary is duplicated here).\n */\nexport type RiskLevel = \"critical\" | \"high\" | \"medium\" | \"low\";\n\n/** A single PTY output frame broadcast on the `pty:data` room event. */\nexport interface PtyDataChunk {\n sessionId: string;\n seq: number;\n data: string;\n cols?: number;\n rows?: number;\n}\n\n/** Ring-buffer snapshot returned by `ptyAttach` for catch-up replay. */\nexport interface PtyAttachSnapshot {\n sessionId: string;\n chunks: { seq: number; data: string }[];\n cols: number;\n rows: number;\n totalBytes: number;\n}\n\n/**\n * Result of `getActivePtySession`. `sessionId` is null until the cloud agent\n * has booted a PTY and produced at least one ring frame (readiness signal).\n */\nexport interface ActivePtySession {\n sessionId: string | null;\n cols?: number;\n rows?: number;\n}\n\nexport interface WorkspaceAttachInfo {\n taskId: string;\n sessionId: string;\n workspaceRoot: string;\n tunnelUrl: string;\n attachToken: string;\n expiresAt: string;\n previewPorts: Array<{ port: number; label: string }>;\n previewUrls: Record<string, string>;\n ssh?: {\n remotePort: number;\n preferredLocalPort: number;\n username: string;\n };\n}\n\n/** One Cloud Logging entry as returned by the API's queryProjectGcpLogs. */\nexport interface GcpLogEntry {\n timestamp: string;\n severity: string;\n message: string;\n resource: Record<string, string>;\n labels: Record<string, string>;\n resourceType?: string;\n insertId?: string;\n trace?: string;\n httpRequest?: { status?: number; method?: string; url?: string; latencyMs?: number };\n payload?: string;\n payloadTruncated?: boolean;\n}\n\nexport interface GcpLogQueryResult {\n entries: GcpLogEntry[];\n hasMore: boolean;\n nextPageToken?: string;\n scopedServices?: string[];\n error?: string;\n}\n\nexport interface MoveCardResult {\n cardId: string;\n sourceProjectId: string;\n destinationProjectId: string;\n slug: string;\n clearedFields: string[];\n}\n\ntype SocketCallback = (response: { success: boolean; data?: unknown; error?: string }) => void;\n\nconst NO_PROJECT_SELECTED_MESSAGE =\n \"No Conveyor project selected. Pass projectId to this tool or configure CONVEYOR_PROJECT_ID.\";\n\n/** Auth failures never recover on retry — match them to fail fast with guidance. */\nconst AUTH_ERROR_RE = /token|unauthor|forbidden|not authenticated|invalid auth/i;\n\n/**\n * Turn a raw server error into an actionable message. Most errors pass through\n * unchanged; the common-but-opaque \"Insufficient permissions\" gets the missing\n * context about why (project role too low) and how to fix it.\n */\nfunction enrichToolError(error?: string, fallback?: string): string {\n const base = error ?? fallback ?? \"Request failed\";\n if (/insufficient permissions/i.test(base)) {\n return (\n `${base}: your Conveyor project role can't perform this action. ` +\n `Creating/updating tasks, builds, and PRs requires Moderate access or higher — ` +\n `ask a project admin to raise your role.`\n );\n }\n return base;\n}\n\nexport class ConveyorConnection {\n private socket: Socket | null = null;\n private config: ConveyorMcpConfig;\n\n constructor(config: ConveyorMcpConfig) {\n this.config = config;\n }\n\n get projectId(): string {\n return this.resolveProjectId();\n }\n\n private resolveProjectId(projectId?: string): string {\n const resolved = projectId ?? this.config.projectId;\n if (!resolved) throw new Error(NO_PROJECT_SELECTED_MESSAGE);\n return resolved;\n }\n\n private normalizeProjectList(response: unknown): unknown[] {\n if (Array.isArray(response)) return response;\n if (typeof response !== \"object\" || response === null) return [];\n const record = response as Record<string, unknown>;\n if (Array.isArray(record.items)) return record.items;\n if (Array.isArray(record.projects)) return record.projects;\n if (Array.isArray(record.data)) return record.data;\n return [];\n }\n\n connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n let settled = false;\n let attempts = 0;\n const maxAttempts = 15;\n\n this.socket = io(this.config.apiUrl, {\n auth: {\n projectToken: this.config.projectToken,\n runnerMode: \"project\",\n },\n transports: [\"websocket\"],\n reconnection: true,\n reconnectionAttempts: Infinity,\n reconnectionDelay: 2000,\n reconnectionDelayMax: 30000,\n randomizationFactor: 0.3,\n extraHeaders: { \"ngrok-skip-browser-warning\": \"true\" },\n });\n\n this.socket.on(\"connect\", () => {\n if (!settled) {\n settled = true;\n // Subscribe to project room for events\n this.socket?.emit(\"projectService:subscribe\", { id: this.config.projectId });\n resolve();\n }\n });\n\n this.socket.on(\"connect_error\", (err) => {\n const message = err?.message ?? \"unknown error\";\n // An auth rejection (e.g. \"Invalid project token\") will never succeed on\n // retry, so fail fast with an actionable message instead of silently\n // retrying for ~30s and then dying with a generic error.\n if (!settled && AUTH_ERROR_RE.test(message)) {\n settled = true;\n this.socket?.close();\n reject(\n new Error(\n `Conveyor rejected the connection: ${message}. The project token is ` +\n `likely invalid or expired — regenerate it in the web app ` +\n `(User Settings → Connect Claude Code) and update CONVEYOR_USER_TOKEN ` +\n `(or legacy CONVEYOR_PROJECT_TOKEN).`,\n ),\n );\n return;\n }\n attempts++;\n if (!settled && attempts >= maxAttempts) {\n settled = true;\n reject(new Error(`Failed to connect to ${this.config.apiUrl}: ${message}`));\n }\n });\n });\n }\n\n // ── Service method call (agentSessionService:*) ─────────────────────\n\n private call<T>(method: string, data: unknown, timeoutMs = 15_000): Promise<T> {\n const socket = this.socket;\n if (!socket) throw new Error(\"Not connected\");\n\n const TIMEOUT_MS = timeoutMs;\n\n return Promise.race([\n new Promise<T>((resolve, reject) => {\n socket.emit(`agentSessionService:${method}`, data, ((response: {\n success: boolean;\n data?: T;\n error?: string;\n }) => {\n if (response.success) {\n resolve(response.data as T);\n } else {\n reject(new Error(enrichToolError(response.error, `${method} failed`)));\n }\n }) as SocketCallback);\n }),\n new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(new Error(`Request timed out: ${method}`));\n }, TIMEOUT_MS);\n }),\n ]);\n }\n\n /**\n * Fire-and-forget emit (no ack). The quickdraw-core server method handler\n * invokes the ack callback via optional chaining, so omitting it still runs\n * the full auth/schema/ACL pipeline — it just skips the response round-trip.\n * Used for high-frequency PTY input/resize so each keystroke does not arm a\n * 15s timeout timer.\n */\n private emit(method: string, data: unknown): void {\n const socket = this.socket;\n if (!socket) throw new Error(\"Not connected\");\n socket.emit(`agentSessionService:${method}`, data);\n }\n\n private callService<T>(\n serviceName: string,\n method: string,\n data: unknown,\n timeoutMs = 15_000,\n ): Promise<T> {\n const socket = this.socket;\n if (!socket) throw new Error(\"Not connected\");\n return Promise.race([\n new Promise<T>((resolve, reject) => {\n socket.emit(`${serviceName}:${method}`, data, ((response: {\n success: boolean;\n data?: T;\n error?: string;\n }) => {\n if (response.success) {\n resolve(response.data as T);\n } else {\n reject(new Error(enrichToolError(response.error, `${method} failed`)));\n }\n }) as SocketCallback);\n }),\n new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(new Error(`Request timed out: ${serviceName}:${method}`));\n }, timeoutMs);\n }),\n ]);\n }\n\n // ── GCP Logs ────────────────────────────────────────────────────────\n\n queryGcpLogs(params: {\n projectId?: string;\n env?: \"prod\" | \"dev\" | \"claudespace\";\n severity?: string;\n services?: string[];\n sqlInstances?: string[];\n allServices?: boolean;\n search?: string;\n filter?: string;\n startTime?: string;\n endTime?: string;\n limit?: number;\n pageToken?: string;\n }): Promise<GcpLogQueryResult> {\n const { projectId, ...rest } = params;\n return this.call(\n \"queryProjectGcpLogs\",\n { projectId: this.resolveProjectId(projectId), ...rest },\n 30_000,\n );\n }\n\n // ── Task Queries ────────────────────────────────────────────────────\n\n listTasks(params: {\n projectId?: string;\n status?: string;\n assigneeId?: string;\n unassigned?: boolean;\n subProjectId?: string;\n limit?: number;\n }): Promise<unknown[]> {\n const { projectId, ...rest } = params;\n return this.call(\"listProjectTasks\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n getTask(taskId: string, projectId?: string): Promise<unknown> {\n return this.call(\"getProjectTask\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n });\n }\n\n getCardBySlug(slug: string, projectId?: string): Promise<unknown> {\n return this.call(\"getProjectTask\", {\n projectId: this.resolveProjectId(projectId),\n taskId: slug,\n });\n }\n\n searchTasks(params: {\n projectId?: string;\n tagNames?: string[];\n searchQuery?: string;\n statusFilters?: string[];\n typeFilters?: string[];\n assigneeId?: string;\n unassigned?: boolean;\n subProjectId?: string;\n limit?: number;\n }): Promise<unknown[]> {\n const { projectId, ...rest } = params;\n return this.call(\"searchProjectTasks\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n // ── Task Mutations ──────────────────────────────────────────────────\n\n createTask(params: {\n projectId?: string;\n title: string;\n description?: string;\n plan?: string;\n status?: string;\n subProjectId?: string;\n }): Promise<{ id: string; slug: string }> {\n const { projectId, ...rest } = params;\n return this.call(\"createProjectTask\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n updateTask(params: {\n projectId?: string;\n taskId: string;\n title?: string;\n plan?: string;\n risk?: RiskLevel | null;\n assignedUserId?: string | null;\n subProjectId?: string | null;\n }): Promise<{ id: string; status: string; risk: RiskLevel | null; assignedUserId: string | null }> {\n const { projectId, ...rest } = params;\n return this.call(\"updateProjectTask\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n /** Guarded status transition used by the review tools (approve/request). */\n transitionTaskStatus(params: {\n projectId?: string;\n taskId: string;\n toStatus: string;\n expectedFromStatus?: string;\n risk?: RiskLevel;\n }): Promise<{ id: string; status: string; risk: RiskLevel | null }> {\n const { projectId, ...rest } = params;\n return this.call(\"transitionProjectTaskStatus\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n moveCard(params: {\n projectId?: string;\n taskId: string;\n destinationProjectId: string;\n }): Promise<MoveCardResult> {\n const { projectId, ...rest } = params;\n return this.call(\"moveProjectCard\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n // ── Reviewers & Members ─────────────────────────────────────────────\n\n addReviewer(params: {\n projectId?: string;\n taskId: string;\n userId: string;\n }): Promise<{ taskId: string; reviewers: Array<{ userId: string; name: string | null }> }> {\n const { projectId, ...rest } = params;\n return this.call(\"addProjectTaskReviewer\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n removeReviewer(params: {\n projectId?: string;\n taskId: string;\n userId: string;\n }): Promise<{ taskId: string; reviewers: Array<{ userId: string; name: string | null }> }> {\n const { projectId, ...rest } = params;\n return this.call(\"removeProjectTaskReviewer\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n listProjectMembers(\n projectId?: string,\n ): Promise<Array<{ userId: string; name: string | null; email: string; level: string }>> {\n return this.call(\"listProjectMembers\", {\n projectId: this.resolveProjectId(projectId),\n });\n }\n\n async listProjects(): Promise<unknown[]> {\n const response = await this.call(\"listAccessibleProjects\", { pageSize: 100 });\n return this.normalizeProjectList(response);\n }\n\n // ── Build Management ────────────────────────────────────────────────\n\n startBuild(taskId: string, projectId?: string): Promise<{ taskId: string; status: string }> {\n return this.call(\"startProjectBuild\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n });\n }\n\n stopBuild(taskId: string, projectId?: string): Promise<{ taskId: string; stopped: boolean }> {\n return this.call(\"stopProjectBuild\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n });\n }\n\n sleepTask(\n taskId: string,\n projectId?: string,\n ): Promise<{ taskId: string; codespaceStatus: string }> {\n return this.callService(\"cloudBuildService\", \"sleepCloudBuild\", {\n taskId,\n projectId: this.resolveProjectId(projectId),\n });\n }\n\n resumeTask(taskId: string, projectId?: string): Promise<{ status: string }> {\n return this.callService(\"cloudBuildService\", \"wakeCodespace\", {\n taskId,\n projectId: this.resolveProjectId(projectId),\n });\n }\n\n deleteTaskEnvironment(\n taskId: string,\n projectId?: string,\n ): Promise<{ taskId: string; status: string }> {\n return this.callService(\"cloudBuildService\", \"deleteTaskEnvironment\", {\n taskId,\n projectId: this.resolveProjectId(projectId),\n });\n }\n\n getBuildStatus(\n taskId: string,\n projectId?: string,\n ): Promise<{\n session: { status: string | null; agentRunnerStatus: string | null } | null;\n }> {\n // Uses getProjectTask and extracts the session field\n return this.call<Record<string, unknown>>(\"getProjectTask\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n }).then((task) => ({\n session:\n (task?.session as {\n status: string | null;\n agentRunnerStatus: string | null;\n }) ?? null,\n }));\n }\n\n getWorkspaceAttachInfo(taskId: string, sshPublicKey?: string): Promise<WorkspaceAttachInfo> {\n return this.callService(\"cloudBuildService\", \"getWorkspaceAttachInfo\", {\n taskId,\n sshPublicKey,\n });\n }\n\n // ── Chat ────────────────────────────────────────────────────────────\n\n getTaskChat(taskId: string, limit?: number, projectId?: string): Promise<unknown[]> {\n // Uses getProjectTask and extracts chatMessages\n return this.call<Record<string, unknown>>(\"getProjectTask\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n }).then((task) => {\n const messages = (task?.chatMessages ?? []) as unknown[];\n return limit ? messages.slice(-limit) : messages;\n });\n }\n\n postToTaskChat(\n taskId: string,\n content: string,\n projectId?: string,\n ): Promise<{ messageId: string }> {\n return this.call(\"postToProjectTaskChat\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n content,\n });\n }\n\n // ── CLI History ─────────────────────────────────────────────────────\n\n getTaskCli(\n taskId: string,\n limit?: number,\n source?: string,\n projectId?: string,\n ): Promise<{ type: string; data: Record<string, unknown>; timestamp: string }[]> {\n return this.call(\"getProjectTaskCli\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n limit,\n source,\n });\n }\n\n // ── Session / Pod State ─────────────────────────────────────────────\n\n getTaskSessions(\n taskId: string,\n projectId?: string,\n ): Promise<\n Array<{\n taskId: string;\n slug: string;\n title: string;\n type: string;\n status: string;\n reviewTargetTaskId: string | null;\n codeReviewStatus: string | null;\n codeReviewAttempts: number;\n workspaces: Array<{\n id: string;\n purpose: string;\n desiredState: string;\n observedState: string;\n branch: string | null;\n checkoutRef: string | null;\n createdAt: string;\n updatedAt: string;\n pod: { name: string; namespace: string; phase: string; imageUri: string | null } | null;\n sessions: Array<{\n id: string;\n role: string;\n mode: string;\n status: string;\n userId: string;\n leaseUntil: string | null;\n createdAt: string;\n }>;\n }>;\n sessions: Array<{\n id: string;\n provider: string;\n instanceName: string | null;\n status: string;\n agentRunnerStatus: string | null;\n lastHeartbeatAt: string | null;\n agentRunningAt: string | null;\n lastAgentEvent: string | null;\n deletionRequestedAt: string | null;\n deletionAttempts: number;\n createdAt: string;\n stoppedAt: string | null;\n }>;\n }>\n > {\n return this.call(\"getProjectTaskSessions\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n });\n }\n\n // ── Project Info ────────────────────────────────────────────────────\n\n listTags(projectId?: string): Promise<{ id: string; name: string; color: string }[]> {\n return this.call(\"listProjectTags\", {\n projectId: this.resolveProjectId(projectId),\n });\n }\n\n getProjectSummary(projectId?: string): Promise<unknown> {\n return this.call(\"getProjectSummary\", {\n projectId: this.resolveProjectId(projectId),\n });\n }\n\n // ── Review Flow ─────────────────────────────────────────────────────\n\n async approveTask(\n taskId: string,\n projectId?: string,\n risk?: RiskLevel,\n ): Promise<{ status: string }> {\n const targetProjectId = this.resolveProjectId(projectId);\n // Determine next status based on current status\n const task = (await this.call(\"getProjectTask\", {\n projectId: targetProjectId,\n taskId,\n })) as { status: string } | null;\n\n if (!task) throw new Error(\"Task not found\");\n\n const nextStatus = task.status === \"ReviewPR\" ? \"ReviewDev\" : \"Complete\";\n\n // Guarded transition; approval attempts a raise-only \"low\" risk by default.\n const result = await this.transitionTaskStatus({\n projectId: targetProjectId,\n taskId,\n toStatus: nextStatus,\n expectedFromStatus: task.status,\n risk: risk ?? \"low\",\n });\n return { status: result.status };\n }\n\n async requestChanges(\n taskId: string,\n feedback: string,\n projectId?: string,\n risk?: RiskLevel,\n ): Promise<void> {\n const targetProjectId = this.resolveProjectId(projectId);\n const task = (await this.call(\"getProjectTask\", {\n projectId: targetProjectId,\n taskId,\n })) as { status: string } | null;\n if (!task) throw new Error(\"Task not found\");\n\n // Post feedback to task chat then move to InProgress via the guarded\n // transition; requested changes attempt a raise-only \"medium\" risk.\n await this.postToTaskChat(taskId, feedback, targetProjectId);\n await this.transitionTaskStatus({\n projectId: targetProjectId,\n taskId,\n toStatus: \"InProgress\",\n expectedFromStatus: task.status,\n risk: risk ?? \"medium\",\n });\n }\n\n approveAndMergePR(\n childTaskId: string,\n projectId?: string,\n ): Promise<{ merged: boolean; childTaskId: string; prNumber: number }> {\n return this.call(\"approveProjectMergePR\", {\n projectId: this.resolveProjectId(projectId),\n childTaskId,\n });\n }\n\n // ── File Attachments ────────────────────────────────────────────────\n\n listTaskFiles(taskId: string, projectId?: string): Promise<unknown[]> {\n return this.call(\"listProjectTaskFiles\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n });\n }\n\n getAttachment(\n taskId: string,\n fileId: string,\n opts?: { offset?: number; maxBytes?: number; projectId?: string },\n ): Promise<unknown> {\n const payload: Record<string, unknown> = {\n projectId: this.resolveProjectId(opts?.projectId),\n taskId,\n fileId,\n };\n if (opts?.offset !== undefined) payload.offset = opts.offset;\n if (opts?.maxBytes !== undefined) payload.maxBytes = opts.maxBytes;\n return this.call(\"getProjectAttachment\", payload);\n }\n\n requestFileUpload(\n taskId: string,\n params: { fileName: string; mimeType: string; fileSize: number; projectId?: string },\n ): Promise<{ fileId: string; uploadUrl: string }> {\n const { projectId, ...rest } = params;\n return this.call(\"requestProjectFileUpload\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n ...rest,\n });\n }\n\n confirmFileUpload(\n taskId: string,\n fileId: string,\n comment?: string,\n projectId?: string,\n ): Promise<{ fileId: string; fileName: string; downloadUrl?: string; messageId?: string }> {\n const payload: Record<string, unknown> = {\n projectId: this.resolveProjectId(projectId),\n taskId,\n fileId,\n };\n if (comment !== undefined) payload.comment = comment;\n // Confirm verifies the object in GCS before marking it uploaded — allow\n // extra headroom for the storage round-trips.\n return this.call(\"confirmProjectFileUpload\", payload, 30_000);\n }\n\n // ── Releases ────────────────────────────────────────────────────────\n\n createRelease(\n taskIds?: string[],\n projectId?: string,\n ): Promise<{ taskId: string; version: string }> {\n // Full releases create the release branch + PR against GitHub synchronously;\n // allow the same headroom as createPullRequest.\n return this.call(\n \"createProjectRelease\",\n { projectId: this.resolveProjectId(projectId), taskIds },\n 45_000,\n );\n }\n\n // ── Pull Requests ───────────────────────────────────────────────────\n\n createPullRequest(params: {\n projectId?: string;\n taskId: string;\n title: string;\n body: string;\n head?: string;\n base?: string;\n }): Promise<{ prNumber: number; prUrl: string }> {\n const { projectId, ...rest } = params;\n // PR creation makes several sequential GitHub API calls (token, create,\n // existing-PR lookup); allow more headroom than the default request timeout.\n return this.call(\n \"createProjectPullRequest\",\n { projectId: this.resolveProjectId(projectId), ...rest },\n 45_000,\n );\n }\n\n // ── Subtasks ────────────────────────────────────────────────────────\n\n createSubtask(params: {\n projectId?: string;\n parentTaskId: string;\n title: string;\n description?: string;\n plan?: string;\n ordinal?: number;\n storyPointValue?: number;\n followParentStatus?: boolean;\n dependsOn?: string[];\n }): Promise<{ id: string; slug: string }> {\n const { projectId, ...rest } = params;\n return this.call(\"createProjectSubtask\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n updateSubtask(params: {\n projectId?: string;\n subtaskId: string;\n title?: string;\n description?: string;\n plan?: string;\n status?: string;\n ordinal?: number;\n storyPointValue?: number;\n followParentStatus?: boolean;\n }): Promise<{ id: string; status: string }> {\n const { projectId, ...rest } = params;\n return this.call(\"updateProjectSubtask\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n listSubtasks(taskId: string, projectId?: string): Promise<unknown[]> {\n return this.call(\"listProjectSubtasks\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n });\n }\n\n deleteSubtask(subtaskId: string, projectId?: string): Promise<{ deleted: boolean }> {\n return this.call(\"deleteProjectSubtask\", {\n projectId: this.resolveProjectId(projectId),\n subtaskId,\n });\n }\n\n // ── Dependencies ────────────────────────────────────────────────────\n\n getDependencies(taskId: string, projectId?: string): Promise<unknown[]> {\n return this.call(\"getProjectTaskDependencies\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n });\n }\n\n addDependency(params: {\n projectId?: string;\n taskId: string;\n dependsOnSlugOrId: string;\n }): Promise<{ success: boolean }> {\n const { projectId, ...rest } = params;\n return this.call(\"addProjectTaskDependency\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n removeDependency(params: {\n projectId?: string;\n taskId: string;\n dependsOnSlugOrId: string;\n }): Promise<{ success: boolean }> {\n const { projectId, ...rest } = params;\n return this.call(\"removeProjectTaskDependency\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n // ── Manual Test Checklist ───────────────────────────────────────────\n\n listManualTests(\n taskId: string,\n projectId?: string,\n ): Promise<\n Array<{\n id: string;\n type: string;\n title: string;\n ordinal: number;\n createdAt: string;\n checked: boolean;\n failures: Array<{ userName: string | null; reason: string | null; createdAt: string }>;\n }>\n > {\n return this.call(\"listProjectManualTests\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n });\n }\n\n setManualTests(\n taskId: string,\n items: Array<{ title: string }>,\n projectId?: string,\n ): Promise<{ created: number; skipped: number }> {\n return this.call(\"setProjectManualTests\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n items,\n });\n }\n\n editManualTest(\n taskId: string,\n title: string,\n newTitle: string,\n projectId?: string,\n ): Promise<{ updated: boolean }> {\n return this.call(\"editProjectManualTest\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n title,\n newTitle,\n });\n }\n\n removeManualTest(\n taskId: string,\n title: string,\n projectId?: string,\n ): Promise<{ removed: boolean }> {\n return this.call(\"removeProjectManualTest\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n title,\n });\n }\n\n approveManualTest(\n taskId: string,\n title: string,\n projectId?: string,\n ): Promise<{ approved: boolean }> {\n return this.call(\"approveProjectManualTest\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n title,\n });\n }\n\n rejectManualTest(\n taskId: string,\n title: string,\n reason: string,\n projectId?: string,\n ): Promise<{ rejected: boolean }> {\n return this.call(\"rejectProjectManualTest\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n title,\n reason,\n });\n }\n\n queryManualTests(params: {\n projectId?: string;\n cardStatuses?: string[];\n testStatuses?: Array<\"open\" | \"approved\" | \"rejected\">;\n }): Promise<\n Array<{\n taskId: string;\n slug: string;\n title: string;\n status: string;\n tests: Array<{\n id: string;\n title: string;\n status: \"open\" | \"approved\" | \"rejected\";\n failures: Array<{ userName: string | null; reason: string | null; createdAt: string }>;\n }>;\n }>\n > {\n const { projectId, ...rest } = params;\n return this.call(\"queryProjectManualTests\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n // ── Suggestions ─────────────────────────────────────────────────────\n\n createSuggestion(params: {\n projectId?: string;\n title: string;\n description?: string;\n tagNames?: string[];\n }): Promise<{ id: string; merged: boolean; mergedIntoId?: string }> {\n const { projectId, ...rest } = params;\n return this.call(\"createProjectSuggestion\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n // ── PTY Tunnel Relay (reuses the S2 pty:* envelope) ─────────────────\n\n /**\n * Poll target: returns the active cloud PTY session for a task once its ring\n * buffer has frames. `sessionId` is resolved server-side from `taskId` (never\n * accepted from the wire), preserving the one-active-session-per-task invariant.\n */\n getActivePtySession(taskId: string): Promise<ActivePtySession> {\n return this.call(\"getActivePtySession\", { taskId });\n }\n\n /** Fetch the ring-buffer snapshot for catch-up replay on (re)attach. */\n ptyAttach(sessionId: string): Promise<PtyAttachSnapshot> {\n return this.call(\"ptyAttach\", { sessionId });\n }\n\n /**\n * Join the session room so `pty:data` frames are delivered. Uses the standard\n * quickdraw-core subscribe envelope; \"Read\" is sufficient for output streaming.\n */\n subscribeToSession(sessionId: string): void {\n const socket = this.socket;\n if (!socket) throw new Error(\"Not connected\");\n socket.emit(\"agentSessionService:subscribe\", {\n entryId: sessionId,\n requiredLevel: \"Read\",\n });\n }\n\n /** Relay a stdin chunk to the cloud PTY (raw utf8, fire-and-forget). */\n ptyInput(sessionId: string, data: string): void {\n this.emit(\"ptyInput\", { sessionId, data });\n }\n\n /** Relay a terminal resize to the cloud PTY (fire-and-forget). */\n ptyResize(sessionId: string, cols: number, rows: number): void {\n this.emit(\"ptyResize\", { sessionId, cols, rows });\n }\n\n /** Subscribe to raw PTY output frames. Returns an unsubscribe function. */\n onPtyData(handler: (chunk: PtyDataChunk) => void): () => void {\n const socket = this.socket;\n if (!socket) throw new Error(\"Not connected\");\n socket.on(\"pty:data\", handler as (...args: unknown[]) => void);\n return () => {\n socket.off(\"pty:data\", handler as (...args: unknown[]) => void);\n };\n }\n\n // ── Connection lifecycle ────────────────────────────────────────────\n\n disconnect(): void {\n this.socket?.disconnect();\n this.socket = null;\n }\n}\n"],"mappings":";AACA,SAAS,UAAuB;AA4FhC,IAAM,8BACJ;AAGF,IAAM,gBAAgB;AAOtB,SAAS,gBAAgB,OAAgB,UAA2B;AAClE,QAAM,OAAO,SAAS,YAAY;AAClC,MAAI,4BAA4B,KAAK,IAAI,GAAG;AAC1C,WACE,GAAG,IAAI;AAAA,EAIX;AACA,SAAO;AACT;AAEO,IAAM,qBAAN,MAAyB;AAAA,EACtB,SAAwB;AAAA,EACxB;AAAA,EAER,YAAY,QAA2B;AACrC,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,IAAI,YAAoB;AACtB,WAAO,KAAK,iBAAiB;AAAA,EAC/B;AAAA,EAEQ,iBAAiB,WAA4B;AACnD,UAAM,WAAW,aAAa,KAAK,OAAO;AAC1C,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,2BAA2B;AAC1D,WAAO;AAAA,EACT;AAAA,EAEQ,qBAAqB,UAA8B;AACzD,QAAI,MAAM,QAAQ,QAAQ,EAAG,QAAO;AACpC,QAAI,OAAO,aAAa,YAAY,aAAa,KAAM,QAAO,CAAC;AAC/D,UAAM,SAAS;AACf,QAAI,MAAM,QAAQ,OAAO,KAAK,EAAG,QAAO,OAAO;AAC/C,QAAI,MAAM,QAAQ,OAAO,QAAQ,EAAG,QAAO,OAAO;AAClD,QAAI,MAAM,QAAQ,OAAO,IAAI,EAAG,QAAO,OAAO;AAC9C,WAAO,CAAC;AAAA,EACV;AAAA,EAEA,UAAyB;AACvB,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAI,UAAU;AACd,UAAI,WAAW;AACf,YAAM,cAAc;AAEpB,WAAK,SAAS,GAAG,KAAK,OAAO,QAAQ;AAAA,QACnC,MAAM;AAAA,UACJ,cAAc,KAAK,OAAO;AAAA,UAC1B,YAAY;AAAA,QACd;AAAA,QACA,YAAY,CAAC,WAAW;AAAA,QACxB,cAAc;AAAA,QACd,sBAAsB;AAAA,QACtB,mBAAmB;AAAA,QACnB,sBAAsB;AAAA,QACtB,qBAAqB;AAAA,QACrB,cAAc,EAAE,8BAA8B,OAAO;AAAA,MACvD,CAAC;AAED,WAAK,OAAO,GAAG,WAAW,MAAM;AAC9B,YAAI,CAAC,SAAS;AACZ,oBAAU;AAEV,eAAK,QAAQ,KAAK,4BAA4B,EAAE,IAAI,KAAK,OAAO,UAAU,CAAC;AAC3E,kBAAQ;AAAA,QACV;AAAA,MACF,CAAC;AAED,WAAK,OAAO,GAAG,iBAAiB,CAAC,QAAQ;AACvC,cAAM,UAAU,KAAK,WAAW;AAIhC,YAAI,CAAC,WAAW,cAAc,KAAK,OAAO,GAAG;AAC3C,oBAAU;AACV,eAAK,QAAQ,MAAM;AACnB;AAAA,YACE,IAAI;AAAA,cACF,qCAAqC,OAAO;AAAA,YAI9C;AAAA,UACF;AACA;AAAA,QACF;AACA;AACA,YAAI,CAAC,WAAW,YAAY,aAAa;AACvC,oBAAU;AACV,iBAAO,IAAI,MAAM,wBAAwB,KAAK,OAAO,MAAM,KAAK,OAAO,EAAE,CAAC;AAAA,QAC5E;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA,EAIQ,KAAQ,QAAgB,MAAe,YAAY,MAAoB;AAC7E,UAAM,SAAS,KAAK;AACpB,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,eAAe;AAE5C,UAAM,aAAa;AAEnB,WAAO,QAAQ,KAAK;AAAA,MAClB,IAAI,QAAW,CAAC,SAAS,WAAW;AAClC,eAAO,KAAK,uBAAuB,MAAM,IAAI,OAAO,CAAC,aAI/C;AACJ,cAAI,SAAS,SAAS;AACpB,oBAAQ,SAAS,IAAS;AAAA,UAC5B,OAAO;AACL,mBAAO,IAAI,MAAM,gBAAgB,SAAS,OAAO,GAAG,MAAM,SAAS,CAAC,CAAC;AAAA,UACvE;AAAA,QACF,EAAoB;AAAA,MACtB,CAAC;AAAA,MACD,IAAI,QAAe,CAAC,GAAG,WAAW;AAChC,mBAAW,MAAM;AACf,iBAAO,IAAI,MAAM,sBAAsB,MAAM,EAAE,CAAC;AAAA,QAClD,GAAG,UAAU;AAAA,MACf,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,KAAK,QAAgB,MAAqB;AAChD,UAAM,SAAS,KAAK;AACpB,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,eAAe;AAC5C,WAAO,KAAK,uBAAuB,MAAM,IAAI,IAAI;AAAA,EACnD;AAAA,EAEQ,YACN,aACA,QACA,MACA,YAAY,MACA;AACZ,UAAM,SAAS,KAAK;AACpB,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,eAAe;AAC5C,WAAO,QAAQ,KAAK;AAAA,MAClB,IAAI,QAAW,CAAC,SAAS,WAAW;AAClC,eAAO,KAAK,GAAG,WAAW,IAAI,MAAM,IAAI,OAAO,CAAC,aAI1C;AACJ,cAAI,SAAS,SAAS;AACpB,oBAAQ,SAAS,IAAS;AAAA,UAC5B,OAAO;AACL,mBAAO,IAAI,MAAM,gBAAgB,SAAS,OAAO,GAAG,MAAM,SAAS,CAAC,CAAC;AAAA,UACvE;AAAA,QACF,EAAoB;AAAA,MACtB,CAAC;AAAA,MACD,IAAI,QAAe,CAAC,GAAG,WAAW;AAChC,mBAAW,MAAM;AACf,iBAAO,IAAI,MAAM,sBAAsB,WAAW,IAAI,MAAM,EAAE,CAAC;AAAA,QACjE,GAAG,SAAS;AAAA,MACd,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,aAAa,QAakB;AAC7B,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK;AAAA,MACV;AAAA,MACA,EAAE,WAAW,KAAK,iBAAiB,SAAS,GAAG,GAAG,KAAK;AAAA,MACvD;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAIA,UAAU,QAOa;AACrB,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK,KAAK,oBAAoB;AAAA,MACnC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,QAAQ,QAAgB,WAAsC;AAC5D,WAAO,KAAK,KAAK,kBAAkB;AAAA,MACjC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,cAAc,MAAc,WAAsC;AAChE,WAAO,KAAK,KAAK,kBAAkB;AAAA,MACjC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAAA,EAEA,YAAY,QAUW;AACrB,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK,KAAK,sBAAsB;AAAA,MACrC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,WAAW,QAO+B;AACxC,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK,KAAK,qBAAqB;AAAA,MACpC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,WAAW,QAQwF;AACjG,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK,KAAK,qBAAqB;AAAA,MACpC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,qBAAqB,QAM+C;AAClE,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK,KAAK,+BAA+B;AAAA,MAC9C,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,SAAS,QAImB;AAC1B,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK,KAAK,mBAAmB;AAAA,MAClC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,YAAY,QAI+E;AACzF,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK,KAAK,0BAA0B;AAAA,MACzC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,eAAe,QAI4E;AACzF,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK,KAAK,6BAA6B;AAAA,MAC5C,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,mBACE,WACuF;AACvF,WAAO,KAAK,KAAK,sBAAsB;AAAA,MACrC,WAAW,KAAK,iBAAiB,SAAS;AAAA,IAC5C,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,eAAmC;AACvC,UAAM,WAAW,MAAM,KAAK,KAAK,0BAA0B,EAAE,UAAU,IAAI,CAAC;AAC5E,WAAO,KAAK,qBAAqB,QAAQ;AAAA,EAC3C;AAAA;AAAA,EAIA,WAAW,QAAgB,WAAiE;AAC1F,WAAO,KAAK,KAAK,qBAAqB;AAAA,MACpC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,UAAU,QAAgB,WAAmE;AAC3F,WAAO,KAAK,KAAK,oBAAoB;AAAA,MACnC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,UACE,QACA,WACsD;AACtD,WAAO,KAAK,YAAY,qBAAqB,mBAAmB;AAAA,MAC9D;AAAA,MACA,WAAW,KAAK,iBAAiB,SAAS;AAAA,IAC5C,CAAC;AAAA,EACH;AAAA,EAEA,WAAW,QAAgB,WAAiD;AAC1E,WAAO,KAAK,YAAY,qBAAqB,iBAAiB;AAAA,MAC5D;AAAA,MACA,WAAW,KAAK,iBAAiB,SAAS;AAAA,IAC5C,CAAC;AAAA,EACH;AAAA,EAEA,sBACE,QACA,WAC6C;AAC7C,WAAO,KAAK,YAAY,qBAAqB,yBAAyB;AAAA,MACpE;AAAA,MACA,WAAW,KAAK,iBAAiB,SAAS;AAAA,IAC5C,CAAC;AAAA,EACH;AAAA,EAEA,eACE,QACA,WAGC;AAED,WAAO,KAAK,KAA8B,kBAAkB;AAAA,MAC1D,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,IACF,CAAC,EAAE,KAAK,CAAC,UAAU;AAAA,MACjB,SACG,MAAM,WAGD;AAAA,IACV,EAAE;AAAA,EACJ;AAAA,EAEA,uBAAuB,QAAgB,cAAqD;AAC1F,WAAO,KAAK,YAAY,qBAAqB,0BAA0B;AAAA,MACrE;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,YAAY,QAAgB,OAAgB,WAAwC;AAElF,WAAO,KAAK,KAA8B,kBAAkB;AAAA,MAC1D,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,IACF,CAAC,EAAE,KAAK,CAAC,SAAS;AAChB,YAAM,WAAY,MAAM,gBAAgB,CAAC;AACzC,aAAO,QAAQ,SAAS,MAAM,CAAC,KAAK,IAAI;AAAA,IAC1C,CAAC;AAAA,EACH;AAAA,EAEA,eACE,QACA,SACA,WACgC;AAChC,WAAO,KAAK,KAAK,yBAAyB;AAAA,MACxC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,WACE,QACA,OACA,QACA,WAC+E;AAC/E,WAAO,KAAK,KAAK,qBAAqB;AAAA,MACpC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,gBACE,QACA,WA8CA;AACA,WAAO,KAAK,KAAK,0BAA0B;AAAA,MACzC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,SAAS,WAA4E;AACnF,WAAO,KAAK,KAAK,mBAAmB;AAAA,MAClC,WAAW,KAAK,iBAAiB,SAAS;AAAA,IAC5C,CAAC;AAAA,EACH;AAAA,EAEA,kBAAkB,WAAsC;AACtD,WAAO,KAAK,KAAK,qBAAqB;AAAA,MACpC,WAAW,KAAK,iBAAiB,SAAS;AAAA,IAC5C,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,MAAM,YACJ,QACA,WACA,MAC6B;AAC7B,UAAM,kBAAkB,KAAK,iBAAiB,SAAS;AAEvD,UAAM,OAAQ,MAAM,KAAK,KAAK,kBAAkB;AAAA,MAC9C,WAAW;AAAA,MACX;AAAA,IACF,CAAC;AAED,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,gBAAgB;AAE3C,UAAM,aAAa,KAAK,WAAW,aAAa,cAAc;AAG9D,UAAM,SAAS,MAAM,KAAK,qBAAqB;AAAA,MAC7C,WAAW;AAAA,MACX;AAAA,MACA,UAAU;AAAA,MACV,oBAAoB,KAAK;AAAA,MACzB,MAAM,QAAQ;AAAA,IAChB,CAAC;AACD,WAAO,EAAE,QAAQ,OAAO,OAAO;AAAA,EACjC;AAAA,EAEA,MAAM,eACJ,QACA,UACA,WACA,MACe;AACf,UAAM,kBAAkB,KAAK,iBAAiB,SAAS;AACvD,UAAM,OAAQ,MAAM,KAAK,KAAK,kBAAkB;AAAA,MAC9C,WAAW;AAAA,MACX;AAAA,IACF,CAAC;AACD,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,gBAAgB;AAI3C,UAAM,KAAK,eAAe,QAAQ,UAAU,eAAe;AAC3D,UAAM,KAAK,qBAAqB;AAAA,MAC9B,WAAW;AAAA,MACX;AAAA,MACA,UAAU;AAAA,MACV,oBAAoB,KAAK;AAAA,MACzB,MAAM,QAAQ;AAAA,IAChB,CAAC;AAAA,EACH;AAAA,EAEA,kBACE,aACA,WACqE;AACrE,WAAO,KAAK,KAAK,yBAAyB;AAAA,MACxC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,cAAc,QAAgB,WAAwC;AACpE,WAAO,KAAK,KAAK,wBAAwB;AAAA,MACvC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,cACE,QACA,QACA,MACkB;AAClB,UAAM,UAAmC;AAAA,MACvC,WAAW,KAAK,iBAAiB,MAAM,SAAS;AAAA,MAChD;AAAA,MACA;AAAA,IACF;AACA,QAAI,MAAM,WAAW,OAAW,SAAQ,SAAS,KAAK;AACtD,QAAI,MAAM,aAAa,OAAW,SAAQ,WAAW,KAAK;AAC1D,WAAO,KAAK,KAAK,wBAAwB,OAAO;AAAA,EAClD;AAAA,EAEA,kBACE,QACA,QACgD;AAChD,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK,KAAK,4BAA4B;AAAA,MAC3C,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,MACA,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,kBACE,QACA,QACA,SACA,WACyF;AACzF,UAAM,UAAmC;AAAA,MACvC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,MACA;AAAA,IACF;AACA,QAAI,YAAY,OAAW,SAAQ,UAAU;AAG7C,WAAO,KAAK,KAAK,4BAA4B,SAAS,GAAM;AAAA,EAC9D;AAAA;AAAA,EAIA,cACE,SACA,WAC8C;AAG9C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,EAAE,WAAW,KAAK,iBAAiB,SAAS,GAAG,QAAQ;AAAA,MACvD;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAIA,kBAAkB,QAO+B;AAC/C,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAG/B,WAAO,KAAK;AAAA,MACV;AAAA,MACA,EAAE,WAAW,KAAK,iBAAiB,SAAS,GAAG,GAAG,KAAK;AAAA,MACvD;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAIA,cAAc,QAU4B;AACxC,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK,KAAK,wBAAwB;AAAA,MACvC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,cAAc,QAU8B;AAC1C,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK,KAAK,wBAAwB;AAAA,MACvC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,aAAa,QAAgB,WAAwC;AACnE,WAAO,KAAK,KAAK,uBAAuB;AAAA,MACtC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,cAAc,WAAmB,WAAmD;AAClF,WAAO,KAAK,KAAK,wBAAwB;AAAA,MACvC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,gBAAgB,QAAgB,WAAwC;AACtE,WAAO,KAAK,KAAK,8BAA8B;AAAA,MAC7C,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,cAAc,QAIoB;AAChC,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK,KAAK,4BAA4B;AAAA,MAC3C,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,iBAAiB,QAIiB;AAChC,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK,KAAK,+BAA+B;AAAA,MAC9C,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,gBACE,QACA,WAWA;AACA,WAAO,KAAK,KAAK,0BAA0B;AAAA,MACzC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,eACE,QACA,OACA,WAC+C;AAC/C,WAAO,KAAK,KAAK,yBAAyB;AAAA,MACxC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,eACE,QACA,OACA,UACA,WAC+B;AAC/B,WAAO,KAAK,KAAK,yBAAyB;AAAA,MACxC,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,iBACE,QACA,OACA,WAC+B;AAC/B,WAAO,KAAK,KAAK,2BAA2B;AAAA,MAC1C,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,kBACE,QACA,OACA,WACgC;AAChC,WAAO,KAAK,KAAK,4BAA4B;AAAA,MAC3C,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,iBACE,QACA,OACA,QACA,WACgC;AAChC,WAAO,KAAK,KAAK,2BAA2B;AAAA,MAC1C,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,iBAAiB,QAiBf;AACA,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK,KAAK,2BAA2B;AAAA,MAC1C,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,iBAAiB,QAKmD;AAClE,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK,KAAK,2BAA2B;AAAA,MAC1C,WAAW,KAAK,iBAAiB,SAAS;AAAA,MAC1C,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,oBAAoB,QAA2C;AAC7D,WAAO,KAAK,KAAK,uBAAuB,EAAE,OAAO,CAAC;AAAA,EACpD;AAAA;AAAA,EAGA,UAAU,WAA+C;AACvD,WAAO,KAAK,KAAK,aAAa,EAAE,UAAU,CAAC;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,mBAAmB,WAAyB;AAC1C,UAAM,SAAS,KAAK;AACpB,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,eAAe;AAC5C,WAAO,KAAK,iCAAiC;AAAA,MAC3C,SAAS;AAAA,MACT,eAAe;AAAA,IACjB,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,SAAS,WAAmB,MAAoB;AAC9C,SAAK,KAAK,YAAY,EAAE,WAAW,KAAK,CAAC;AAAA,EAC3C;AAAA;AAAA,EAGA,UAAU,WAAmB,MAAc,MAAoB;AAC7D,SAAK,KAAK,aAAa,EAAE,WAAW,MAAM,KAAK,CAAC;AAAA,EAClD;AAAA;AAAA,EAGA,UAAU,SAAoD;AAC5D,UAAM,SAAS,KAAK;AACpB,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,eAAe;AAC5C,WAAO,GAAG,YAAY,OAAuC;AAC7D,WAAO,MAAM;AACX,aAAO,IAAI,YAAY,OAAuC;AAAA,IAChE;AAAA,EACF;AAAA;AAAA,EAIA,aAAmB;AACjB,SAAK,QAAQ,WAAW;AACxB,SAAK,SAAS;AAAA,EAChB;AACF;","names":[]}
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ConveyorConnection
4
- } from "./chunk-3HM7WTJR.js";
4
+ } from "./chunk-HRIOQERY.js";
5
5
 
6
6
  // src/cli.ts
7
7
  import { createRequire } from "module";
@@ -114,6 +114,7 @@ var STATUS_ENUM = [
114
114
  "Cancelled"
115
115
  ];
116
116
  var CARD_TYPE_ENUM = ["task", "incident", "suggestion"];
117
+ var RISK_ENUM = ["critical", "high", "medium", "low"];
117
118
  function registerListTasks(server2, conn2) {
118
119
  server2.tool(
119
120
  "list_tasks",
@@ -189,14 +190,15 @@ function registerCreateTask(server2, conn2) {
189
190
  function registerUpdateTask(server2, conn2) {
190
191
  server2.tool(
191
192
  "update_task",
192
- "Update task fields: title, description, plan, status, or assignment. Pass projectId to target a specific project; otherwise the configured default project is used. Moving a task beyond Planning auto-fills any missing icon, story points, and agent assignment \u2014 don't spend turns on them.",
193
+ "Update task fields: title, plan, risk, or assignment. Status and description are NOT editable through MCP \u2014 use approve_task / request_changes for review status moves. Pass projectId to target a specific project; otherwise the configured default project is used.",
193
194
  {
194
195
  projectId: z2.string().optional().describe("Target Conveyor project ID"),
195
196
  taskId: z2.string().describe("The task ID"),
196
197
  title: z2.string().optional().describe("New title"),
197
- description: z2.string().optional().describe("New description"),
198
198
  plan: z2.string().optional().describe("New plan (markdown)"),
199
- status: z2.enum(STATUS_ENUM).optional().describe("New status"),
199
+ risk: z2.enum(RISK_ENUM).nullable().optional().describe(
200
+ "Risk level \u2014 how much important surface the task touches (critical/high/medium/low). Pass null to clear."
201
+ ),
200
202
  assignedUserId: z2.string().nullable().optional().describe("User ID to assign, or null"),
201
203
  subProjectId: z2.string().nullable().optional().describe(
202
204
  "Assign the task to a sub-project board; null moves it back to the parent board. Omit to leave unchanged."
@@ -210,6 +212,29 @@ function registerUpdateTask(server2, conn2) {
210
212
  }
211
213
  );
212
214
  }
215
+ function registerMoveCard(server2, conn2) {
216
+ server2.tool(
217
+ "move_card",
218
+ "Move an eligible Planning or Open task, incident, or suggestion card to another project. Cards with identification or automation in progress, active compute, pull requests, deployments, releases, reviews, or delivered reporter email cannot move. Project-specific metadata is cleared instead of mapped by name. Pass projectId for the source project; otherwise the configured default project is used.",
219
+ {
220
+ projectId: z2.string().optional().describe("Source Conveyor project ID"),
221
+ taskId: z2.string().describe("Card ID or slug"),
222
+ destinationProjectId: z2.string().describe("Destination Conveyor project ID")
223
+ },
224
+ async (params) => {
225
+ const result = await conn2.moveCard(params);
226
+ const clearedFields = result.clearedFields.length > 0 ? result.clearedFields.join(", ") : "none";
227
+ return {
228
+ content: [
229
+ {
230
+ type: "text",
231
+ text: `Card moved as ${result.slug} to project ${result.destinationProjectId}. Cleared fields: ${clearedFields}`
232
+ }
233
+ ]
234
+ };
235
+ }
236
+ );
237
+ }
213
238
  function registerChatTools(server2, conn2) {
214
239
  server2.tool(
215
240
  "read_task_chat",
@@ -327,10 +352,11 @@ function registerReviewTools(server2, conn2) {
327
352
  "Move a task forward in the review flow (ReviewPR -> ReviewDev, or -> Complete). Pass projectId to target a specific project; otherwise the configured default project is used.",
328
353
  {
329
354
  projectId: z2.string().optional().describe("Target Conveyor project ID"),
330
- taskId: z2.string().describe("The task ID")
355
+ taskId: z2.string().describe("The task ID"),
356
+ risk: z2.enum(RISK_ENUM).optional().describe("Optional risk level to record; defaults to a raise-only 'low' on approval.")
331
357
  },
332
358
  async (params) => {
333
- const result = await conn2.approveTask(params.taskId, params.projectId);
359
+ const result = await conn2.approveTask(params.taskId, params.projectId, params.risk);
334
360
  return {
335
361
  content: [{ type: "text", text: `Task approved, new status: ${result.status}` }]
336
362
  };
@@ -361,10 +387,11 @@ function registerReviewTools(server2, conn2) {
361
387
  {
362
388
  projectId: z2.string().optional().describe("Target Conveyor project ID"),
363
389
  taskId: z2.string().describe("The task ID"),
364
- feedback: z2.string().describe("Feedback message describing requested changes")
390
+ feedback: z2.string().describe("Feedback message describing requested changes"),
391
+ risk: z2.enum(RISK_ENUM).optional().describe("Optional risk level to record; defaults to a raise-only 'medium' on changes.")
365
392
  },
366
393
  async (params) => {
367
- await conn2.requestChanges(params.taskId, params.feedback, params.projectId);
394
+ await conn2.requestChanges(params.taskId, params.feedback, params.projectId, params.risk);
368
395
  return { content: [{ type: "text", text: "Changes requested, task moved to InProgress" }] };
369
396
  }
370
397
  );
@@ -421,6 +448,7 @@ function registerTaskTools(server2, conn2) {
421
448
  registerGetCardBySlug(server2, conn2);
422
449
  registerCreateTask(server2, conn2);
423
450
  registerUpdateTask(server2, conn2);
451
+ registerMoveCard(server2, conn2);
424
452
  registerChatTools(server2, conn2);
425
453
  registerGetTaskCli(server2, conn2);
426
454
  registerGetTaskSessions(server2, conn2);
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/tools/project.ts","../src/tools/tasks.ts","../src/tools/builds.ts","../src/tools/attachments.ts","../src/tools/pull-request.ts","../src/tools/subtasks.ts","../src/tools/dependencies.ts","../src/tools/suggestions.ts","../src/tools/checklists.ts","../src/tools/workspace.ts","../src/workspace-ssh-tunnel.ts","../src/tools/logs.ts","../src/tools/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { createRequire } from \"node:module\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { ConveyorConnection } from \"./connection.js\";\nimport { registerAllTools } from \"./tools/index.js\";\n\nconst { version } = createRequire(import.meta.url)(\"../package.json\") as { version: string };\n\nconst apiUrl = process.env.CONVEYOR_API_URL;\nconst projectToken = process.env.CONVEYOR_USER_TOKEN ?? process.env.CONVEYOR_PROJECT_TOKEN;\nconst projectId = process.env.CONVEYOR_PROJECT_ID;\n\nif (!apiUrl || !projectToken) {\n process.stderr.write(\n \"Error: CONVEYOR_API_URL and CONVEYOR_USER_TOKEN or CONVEYOR_PROJECT_TOKEN environment variables are required. CONVEYOR_PROJECT_ID is optional and sets the default project.\\n\",\n );\n process.exit(1);\n}\n\nconst conn = new ConveyorConnection({ apiUrl, projectToken, projectId });\n\ntry {\n await conn.connect();\n process.stderr.write(\"Connected to Conveyor API\\n\");\n} catch (err) {\n process.stderr.write(`Failed to connect to Conveyor API: ${err}\\n`);\n process.exit(1);\n}\n\nconst server = new McpServer({\n name: \"conveyor\",\n version,\n});\n\nregisterAllTools(server, conn);\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n\nprocess.on(\"SIGINT\", () => {\n conn.disconnect();\n process.exit(0);\n});\n\nprocess.on(\"SIGTERM\", () => {\n conn.disconnect();\n process.exit(0);\n});\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\n\nexport function registerProjectTools(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"list_projects\",\n \"List Conveyor projects available to this MCP token's user. Use a returned project id as projectId on other tools when no default project is configured or when targeting a different project.\",\n {},\n async () => {\n const projects = await conn.listProjects();\n return { content: [{ type: \"text\", text: JSON.stringify(projects, null, 2) }] };\n },\n );\n\n server.tool(\n \"get_project_summary\",\n \"Get overall project status: task counts by status, active builds, repo info. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n },\n async (params) => {\n const summary = await conn.getProjectSummary(params.projectId);\n return { content: [{ type: \"text\", text: JSON.stringify(summary, null, 2) }] };\n },\n );\n\n server.tool(\n \"list_project_members\",\n \"List project members with user ID, name, email, and access level — use to resolve a person's name or email to a user ID for task assignment or review. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n },\n async (params) => {\n const members = await conn.listProjectMembers(params.projectId);\n return { content: [{ type: \"text\", text: JSON.stringify(members, null, 2) }] };\n },\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\n\nconst CLI_EVENT_FORMATTERS: Record<string, (data: Record<string, unknown>) => string> = {\n thinking: (data) => String(data.message ?? \"\"),\n tool_use: (data) => `${data.tool}: ${String(data.input ?? \"\").slice(0, 1000)}`,\n tool_result: (data) =>\n `${data.tool} → ${String(data.output ?? \"\").slice(0, 500)}${data.isError ? \" [ERROR]\" : \"\"}`,\n message: (data) => String(data.content ?? \"\"),\n error: (data) => `ERROR: ${String(data.message ?? \"\")}`,\n completed: (data) =>\n `Completed: ${data.summary ?? \"\"} (cost: $${data.costUsd ?? \"?\"}, duration: ${data.durationMs ?? \"?\"}ms)`,\n setup_output: (data) => `[${data.stream ?? \"stdout\"}] ${String(data.data ?? \"\")}`,\n start_command_output: (data) => `[${data.stream ?? \"stdout\"}] ${String(data.data ?? \"\")}`,\n turn_end: (data) =>\n `Turn complete (${Array.isArray(data.toolCalls) ? data.toolCalls.length : 0} tool calls)`,\n};\n\nfunction formatCliEventSummary(type: string, data: Record<string, unknown>): string {\n const formatter = CLI_EVENT_FORMATTERS[type];\n return formatter ? formatter(data) : JSON.stringify(data);\n}\n\ntype TaskSessionState = Awaited<ReturnType<ConveyorConnection[\"getTaskSessions\"]>>[number];\ntype LegacyComputeSession = TaskSessionState[\"sessions\"][number];\ntype WorkspaceState = TaskSessionState[\"workspaces\"][number];\ntype WorkspaceSessionState = WorkspaceState[\"sessions\"][number];\n\nfunction formatLegacyComputeSession(s: LegacyComputeSession): string {\n return (\n ` - session ${s.id} [${s.provider}] pod=${s.instanceName ?? \"-\"} status=${s.status}` +\n ` runner=${s.agentRunnerStatus ?? \"-\"} lastHeartbeat=${s.lastHeartbeatAt ?? \"-\"}` +\n ` created=${s.createdAt} stopped=${s.stoppedAt ?? \"-\"}` +\n (s.deletionRequestedAt\n ? ` deletionRequested=${s.deletionRequestedAt} (attempts ${s.deletionAttempts})`\n : \"\") +\n (s.lastAgentEvent ? ` lastAgentEvent=${s.lastAgentEvent}` : \"\")\n );\n}\n\nfunction formatWorkspaceSession(s: WorkspaceSessionState): string {\n return (\n ` - workspaceSession ${s.id} role=${s.role} mode=${s.mode}` +\n ` status=${s.status} leaseUntil=${s.leaseUntil ?? \"-\"} created=${s.createdAt}`\n );\n}\n\nfunction formatWorkspace(w: WorkspaceState): string[] {\n const lines = [\n ` - workspace ${w.id} purpose=${w.purpose} desired=${w.desiredState}` +\n ` observed=${w.observedState} branch=${w.branch ?? \"-\"} checkoutRef=${w.checkoutRef ?? \"-\"}` +\n (w.pod ? ` pod=${w.pod.namespace}/${w.pod.name} podPhase=${w.pod.phase}` : \" pod=-\"),\n ];\n if (w.sessions.length === 0) {\n lines.push(\" (no workspace sessions)\");\n return lines;\n }\n lines.push(...w.sessions.map(formatWorkspaceSession));\n return lines;\n}\n\nfunction formatTaskSessionState(t: TaskSessionState): string[] {\n const review = t.codeReviewStatus\n ? ` codeReview=${t.codeReviewStatus} (attempts ${t.codeReviewAttempts})`\n : \"\";\n const kind = t.reviewTargetTaskId ? `review card for ${t.reviewTargetTaskId}` : t.type;\n const lines = [`# ${t.slug} — ${t.title} [${kind}, status ${t.status}]${review}`];\n if (t.sessions.length === 0) {\n lines.push(\" (no compute sessions)\");\n } else {\n lines.push(...t.sessions.map(formatLegacyComputeSession));\n }\n if (t.workspaces.length === 0) {\n lines.push(\" (no v3 workspaces)\");\n } else {\n lines.push(...t.workspaces.flatMap(formatWorkspace));\n }\n return lines;\n}\n\nconst DESCRIPTION_PREVIEW_CHARS = 300;\n\n/** List/search results omit `plan` and truncate `description` — `get_task` returns the full record. */\nfunction summarizeTask(task: unknown): unknown {\n if (typeof task !== \"object\" || task === null) return task;\n const { plan, description, ...rest } = task as Record<string, unknown>;\n const summary: Record<string, unknown> = { ...rest };\n summary.description =\n typeof description === \"string\" && description.length > DESCRIPTION_PREVIEW_CHARS\n ? `${description.slice(0, DESCRIPTION_PREVIEW_CHARS)}… [truncated — use get_task for the full description]`\n : (description ?? null);\n summary.hasPlan = typeof plan === \"string\" && plan.length > 0;\n return summary;\n}\n\nconst STATUS_ENUM = [\n \"Planning\",\n \"Open\",\n \"InProgress\",\n \"ReviewPR\",\n \"ReviewDev\",\n \"ReviewLive\",\n \"Complete\",\n \"Cancelled\",\n] as const;\n\nconst CARD_TYPE_ENUM = [\"task\", \"incident\", \"suggestion\"] as const;\n\nfunction registerListTasks(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"list_tasks\",\n \"List project tasks, optionally filtered by status or assignment (a specific assignee, or unassigned tasks). Pass projectId to target a specific project; otherwise the configured default project is used. Returns summaries — plan omitted, description truncated; use get_task for full details.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n status: z.enum(STATUS_ENUM).optional().describe(\"Filter by task status\"),\n assigneeId: z.string().optional().describe(\"Filter by assigned user ID\"),\n unassigned: z\n .boolean()\n .optional()\n .describe(\"Only return tasks with no assignee (mutually exclusive with assigneeId)\"),\n subProjectId: z\n .string()\n .optional()\n .describe(\n \"Scope to a sub-project board (list/search: filter; create/update: assign). Omit for the whole project.\",\n ),\n limit: z.number().optional().describe(\"Max tasks to return (default 50)\"),\n },\n async (params) => {\n const tasks = await conn.listTasks(params);\n return {\n content: [{ type: \"text\", text: JSON.stringify(tasks.map(summarizeTask), null, 2) }],\n };\n },\n );\n}\n\nfunction registerGetTask(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"get_task\",\n \"Get full task details including plan, chat history, PR info, subtasks, and build status. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug (the value in a card URL, /cards/<slug>)\"),\n },\n async (params) => {\n const task = await conn.getTask(params.taskId, params.projectId);\n return { content: [{ type: \"text\", text: JSON.stringify(task, null, 2) }] };\n },\n );\n}\n\nfunction registerGetCardBySlug(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"get_card_by_slug\",\n \"Get full card details by the slug from a card URL (/cards/<slug>) instead of a task ID. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n slug: z.string().describe(\"The card slug from a Conveyor card URL, e.g. 'ship-it'\"),\n },\n async (params) => {\n const task = await conn.getCardBySlug(params.slug, params.projectId);\n return { content: [{ type: \"text\", text: JSON.stringify(task, null, 2) }] };\n },\n );\n}\n\nfunction registerCreateTask(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"create_task\",\n \"Create a new task with title, description, and optional plan. Pass projectId to target a specific project; otherwise the configured default project is used. Icon, story points, and agent assignment are auto-filled when a task is created in (or later moved to) a status beyond Planning — don't spend turns on them.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n title: z.string().describe(\"Task title\"),\n description: z.string().optional().describe(\"Task description\"),\n plan: z.string().optional().describe(\"Task implementation plan (markdown)\"),\n status: z\n .enum([\"Planning\", \"Open\"])\n .optional()\n .describe(\"Initial status (default: Planning)\"),\n subProjectId: z\n .string()\n .optional()\n .describe(\n \"Scope to a sub-project board (list/search: filter; create/update: assign). Omit for the whole project.\",\n ),\n },\n async (params) => {\n const task = await conn.createTask(params);\n return {\n content: [{ type: \"text\", text: `Task created: ${task.id} (slug: ${task.slug})` }],\n };\n },\n );\n}\n\nfunction registerUpdateTask(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"update_task\",\n \"Update task fields: title, description, plan, status, or assignment. Pass projectId to target a specific project; otherwise the configured default project is used. Moving a task beyond Planning auto-fills any missing icon, story points, and agent assignment — don't spend turns on them.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n title: z.string().optional().describe(\"New title\"),\n description: z.string().optional().describe(\"New description\"),\n plan: z.string().optional().describe(\"New plan (markdown)\"),\n status: z.enum(STATUS_ENUM).optional().describe(\"New status\"),\n assignedUserId: z.string().nullable().optional().describe(\"User ID to assign, or null\"),\n subProjectId: z\n .string()\n .nullable()\n .optional()\n .describe(\n \"Assign the task to a sub-project board; null moves it back to the parent board. Omit to leave unchanged.\",\n ),\n },\n async (params) => {\n const result = await conn.updateTask(params);\n return {\n content: [{ type: \"text\", text: `Task ${result.id} updated (status: ${result.status})` }],\n };\n },\n );\n}\n\nfunction registerChatTools(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"read_task_chat\",\n \"Read messages from a task's chat. Pass projectId to target a specific project; otherwise the configured default project is used. For agent execution logs use get_task_logs.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n limit: z.number().optional().describe(\"Max messages to return (default 50)\"),\n },\n async (params) => {\n const messages = await conn.getTaskChat(params.taskId, params.limit, params.projectId);\n return { content: [{ type: \"text\", text: JSON.stringify(messages, null, 2) }] };\n },\n );\n\n server.tool(\n \"post_to_chat\",\n \"Post a message to a task's chat. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n content: z.string().describe(\"Message content\"),\n },\n async (params) => {\n await conn.postToTaskChat(params.taskId, params.content, params.projectId);\n return { content: [{ type: \"text\", text: \"Message posted\" }] };\n },\n );\n}\n\nfunction registerGetTaskCli(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"get_task_logs\",\n \"Read CLI execution logs from a task. Pass projectId to target a specific project; otherwise the configured default project is used. Returns agent reasoning, tool calls, setup output, and other execution events. For human chat use read_task_chat.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n source: z\n .enum([\"agent\", \"application\"])\n .optional()\n .describe(\n \"Filter by log source: 'agent' for reasoning/tool calls, 'application' for setup/dev-server output\",\n ),\n limit: z.number().optional().describe(\"Max entries to return (default 50, max 500)\"),\n },\n async ({ taskId, source, limit, projectId }) => {\n const effectiveLimit = Math.min(limit ?? 50, 500);\n const logs = await conn.getTaskCli(taskId, effectiveLimit, source, projectId);\n const formatted = logs\n .map((log) => {\n return `[${log.timestamp}] [${log.type}] ${formatCliEventSummary(log.type, log.data)}`;\n })\n .join(\"\\n\");\n return {\n content: [{ type: \"text\" as const, text: formatted || \"No CLI logs found for this task.\" }],\n };\n },\n );\n}\n\nfunction registerGetTaskSessions(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"get_task_sessions\",\n \"Read compute-session state for a task: legacy CodespaceSession rows plus v3 workspaces, including purpose=review review workspaces. Shows pod identity, liveness, lifecycle, and code-review claim state. Use to diagnose stalled/dead agents or code-review runs. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n },\n async ({ taskId, projectId }) => {\n const tasks = await conn.getTaskSessions(taskId, projectId);\n const lines = tasks.flatMap(formatTaskSessionState);\n return {\n content: [\n { type: \"text\" as const, text: lines.join(\"\\n\") || \"No sessions found for this task.\" },\n ],\n };\n },\n );\n}\n\nfunction registerSearchTasks(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"search_tasks\",\n \"Search cards by tag name, text query, status, type, and/or assignment. Defaults to type=task — pass typeFilters to include incidents/suggestions. Pass projectId to target a specific project; otherwise the configured default project is used. Use tag names like 'agent-runner', not IDs. Returns summaries — plan omitted, description truncated; use get_task for full details.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n tagNames: z\n .array(z.string())\n .optional()\n .describe('Tag names to filter by (e.g., [\"agent-runner\", \"chat\"])'),\n searchQuery: z.string().optional().describe(\"Text search on title and description\"),\n statusFilters: z\n .array(z.enum(STATUS_ENUM))\n .optional()\n .describe(\"Filter by one or more statuses\"),\n typeFilters: z\n .array(z.enum(CARD_TYPE_ENUM))\n .optional()\n .describe(\n 'Card types to include (default [\"task\"]). Pass e.g. [\"incident\"] or list several to search across types.',\n ),\n assigneeId: z.string().optional().describe(\"Filter by assigned user ID\"),\n unassigned: z\n .boolean()\n .optional()\n .describe(\"Only return tasks with no assignee (mutually exclusive with assigneeId)\"),\n subProjectId: z\n .string()\n .optional()\n .describe(\n \"Scope to a sub-project board (list/search: filter; create/update: assign). Omit for the whole project.\",\n ),\n limit: z.number().optional().describe(\"Max results to return (default 20)\"),\n },\n async (params) => {\n const tasks = await conn.searchTasks(params);\n return {\n content: [{ type: \"text\", text: JSON.stringify(tasks.map(summarizeTask), null, 2) }],\n };\n },\n );\n}\n\nfunction registerListTags(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"list_tags\",\n \"List all project tags with their names, IDs, and colors. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n },\n async (params) => {\n const tags = await conn.listTags(params.projectId);\n return { content: [{ type: \"text\", text: JSON.stringify(tags, null, 2) }] };\n },\n );\n}\n\nfunction registerReviewTools(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"approve_task\",\n \"Move a task forward in the review flow (ReviewPR -> ReviewDev, or -> Complete). Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n },\n async (params) => {\n const result = await conn.approveTask(params.taskId, params.projectId);\n return {\n content: [{ type: \"text\", text: `Task approved, new status: ${result.status}` }],\n };\n },\n );\n\n server.tool(\n \"approve_and_merge_pr\",\n \"Approve and merge a child task's pull request. Pass projectId to target a specific project; otherwise the configured default project is used. Only succeeds if all CI/CD checks are passing. The child task must be in ReviewPR status with a PR.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n childTaskId: z.string().describe(\"The child task ID whose PR should be approved and merged\"),\n },\n async (params) => {\n const result = await conn.approveAndMergePR(params.childTaskId, params.projectId);\n return {\n content: [\n {\n type: \"text\",\n text: `PR #${result.prNumber} approved and merged for task ${result.childTaskId}`,\n },\n ],\n };\n },\n );\n\n server.tool(\n \"request_changes\",\n \"Post feedback and send task back to InProgress for more work. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n feedback: z.string().describe(\"Feedback message describing requested changes\"),\n },\n async (params) => {\n await conn.requestChanges(params.taskId, params.feedback, params.projectId);\n return { content: [{ type: \"text\", text: \"Changes requested, task moved to InProgress\" }] };\n },\n );\n}\n\nfunction formatReviewerList(reviewers: Array<{ userId: string; name: string | null }>): string {\n if (reviewers.length === 0) return \"none\";\n return reviewers.map((r) => `${r.name ?? \"unknown\"} (${r.userId})`).join(\", \");\n}\n\nfunction registerReviewerTools(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"add_reviewer\",\n \"Add a project member as a reviewer on a task. Pass projectId to target a specific project; otherwise the configured default project is used. Idempotent — adding an existing reviewer is a no-op.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n userId: z\n .string()\n .describe(\"User ID of the reviewer (use list_project_members to resolve a name or email)\"),\n },\n async (params) => {\n const result = await conn.addReviewer(params);\n return {\n content: [\n {\n type: \"text\",\n text: `Reviewer added to task ${result.taskId}. Reviewers: ${formatReviewerList(result.reviewers)}`,\n },\n ],\n };\n },\n );\n\n server.tool(\n \"remove_reviewer\",\n \"Remove a reviewer from a task. Pass projectId to target a specific project; otherwise the configured default project is used. Idempotent — removing a non-reviewer is a no-op.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n userId: z.string().describe(\"User ID of the reviewer to remove\"),\n },\n async (params) => {\n const result = await conn.removeReviewer(params);\n return {\n content: [\n {\n type: \"text\",\n text: `Reviewer removed from task ${result.taskId}. Reviewers: ${formatReviewerList(result.reviewers)}`,\n },\n ],\n };\n },\n );\n}\n\nexport function registerTaskTools(server: McpServer, conn: ConveyorConnection): void {\n registerListTasks(server, conn);\n registerGetTask(server, conn);\n registerGetCardBySlug(server, conn);\n registerCreateTask(server, conn);\n registerUpdateTask(server, conn);\n registerChatTools(server, conn);\n registerGetTaskCli(server, conn);\n registerGetTaskSessions(server, conn);\n registerSearchTasks(server, conn);\n registerListTags(server, conn);\n registerReviewTools(server, conn);\n registerReviewerTools(server, conn);\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\n\nfunction textResult(result: unknown): { content: Array<{ type: \"text\"; text: string }> } {\n return { content: [{ type: \"text\", text: JSON.stringify(result, null, 2) }] };\n}\n\nfunction registerTaskLifecycleTools(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"stop_task\",\n \"Compatibility alias for the legacy stop path. stop_task now performs the same durable sleep behavior as sleep_task, preserving task Claudespace state while stopping compute. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n },\n async (params) => textResult(await conn.sleepTask(params.taskId, params.projectId)),\n );\n\n server.tool(\n \"sleep_task\",\n \"Sleep a task Claudespace, stopping compute while preserving durable state. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n },\n async (params) => textResult(await conn.sleepTask(params.taskId, params.projectId)),\n );\n\n server.tool(\n \"resume_task\",\n \"Resume a sleeping task Claudespace. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n },\n async (params) => textResult(await conn.resumeTask(params.taskId, params.projectId)),\n );\n\n server.tool(\n \"delete_task_environment\",\n \"Delete a task environment, including durable Claudespace state. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n },\n async (params) => textResult(await conn.deleteTaskEnvironment(params.taskId, params.projectId)),\n );\n}\n\nexport function registerBuildTools(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"start_task\",\n \"Start a cloud build (codespace) for a task. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n },\n async (params) => {\n const result = await conn.startBuild(params.taskId, params.projectId);\n return textResult(result);\n },\n );\n\n registerTaskLifecycleTools(server, conn);\n\n server.tool(\n \"create_release\",\n \"Create a release for the project — the same flow as the Release button in the web UI. Pass projectId to target a specific project; otherwise the configured default project is used. Creates a release task with a release/YYYY.MM.N branch and a PR from the dev branch to the default branch. Omit taskIds to release ALL cards currently in Review (Dev); pass a subset to cherry-pick — a cloud build agent then cherry-picks those changes and resolves conflicts. Fails if a release is already in progress or no cards are in Review (Dev).\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskIds: z\n .array(z.string())\n .optional()\n .describe(\n \"Task IDs in Review (Dev) to cherry-pick into the release. Omit to release all of them.\",\n ),\n },\n async (params) => {\n const result = await conn.createRelease(params.taskIds, params.projectId);\n return textResult(result);\n },\n );\n\n server.tool(\n \"get_build_status\",\n \"Check codespace and agent status for a task. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n },\n async (params) => {\n const status = await conn.getBuildStatus(params.taskId, params.projectId);\n return textResult(status);\n },\n );\n}\n","import { readFile, stat } from \"node:fs/promises\";\nimport { basename, extname } from \"node:path\";\nimport { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\n\n// Mirrors MAX_FILE_SIZE_BYTES in @project/shared service-map.ts (conveyor-mcp\n// has no workspace dependencies — the server enforces the real limit).\nconst MAX_FILE_SIZE_BYTES = 25 * 1024 * 1024;\n\nconst MIME_BY_EXT: Record<string, string> = {\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".svg\": \"image/svg+xml\",\n \".txt\": \"text/plain\",\n \".log\": \"text/plain\",\n \".md\": \"text/markdown\",\n \".csv\": \"text/csv\",\n \".html\": \"text/html\",\n \".css\": \"text/css\",\n \".js\": \"text/javascript\",\n \".ts\": \"text/plain\",\n \".json\": \"application/json\",\n \".yaml\": \"application/yaml\",\n \".yml\": \"application/yaml\",\n \".pdf\": \"application/pdf\",\n \".zip\": \"application/zip\",\n \".gz\": \"application/gzip\",\n \".mp4\": \"video/mp4\",\n \".webm\": \"video/webm\",\n \".mp3\": \"audio/mpeg\",\n \".wav\": \"audio/wav\",\n};\n\nexport function inferMimeType(filePath: string, override?: string): string {\n if (override) return override;\n return MIME_BY_EXT[extname(filePath).toLowerCase()] ?? \"application/octet-stream\";\n}\n\nfunction registerListTaskFiles(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"list_task_files\",\n \"List all files attached to a task with metadata (no contents — fast and small). Pass projectId to target a specific project; otherwise the configured default project is used. Use before fetching a specific file to see what is available and how large each is. For file contents use get_attachment.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n },\n async (params) => {\n const files = await conn.listTaskFiles(params.taskId, params.projectId);\n return { content: [{ type: \"text\", text: JSON.stringify(files, null, 2) }] };\n },\n );\n}\n\nexport interface AttachmentResult {\n fileName?: string;\n mimeType?: string;\n fileSize?: number;\n content?: string;\n contentEncoding?: string;\n contentByteOffset?: number;\n contentTotalBytes?: number;\n contentTruncated?: boolean;\n downloadUrl?: string;\n}\n\nexport type AttachmentContentBlock =\n | { type: \"text\"; text: string }\n | { type: \"image\"; data: string; mimeType: string };\n\nfunction buildTextContent(file: AttachmentResult, content: string): AttachmentContentBlock[] {\n const start = file.contentByteOffset ?? 0;\n const shown = Buffer.byteLength(content, \"utf-8\");\n const total = file.contentTotalBytes ?? shown;\n const more = file.contentTruncated\n ? ` — showing bytes ${start}–${start + shown} of ${total}; pass offset=${start + shown} for the next page, or fetch the full file at downloadUrl`\n : \"\";\n const header = `${file.fileName ?? \"file\"} (${file.mimeType ?? \"?\"}, ${total} bytes)${more}\\n${file.downloadUrl ? `downloadUrl: ${file.downloadUrl}\\n` : \"\"}---\\n`;\n return [{ type: \"text\", text: header + content }];\n}\n\nfunction buildImageContent(\n file: AttachmentResult,\n content: string,\n mimeType: string,\n): AttachmentContentBlock[] {\n const header = `${file.fileName ?? \"file\"} (${mimeType}, ${file.fileSize ?? \"?\"} bytes)${file.downloadUrl ? `\\ndownloadUrl: ${file.downloadUrl}` : \"\"}`;\n return [\n { type: \"text\", text: header },\n { type: \"image\", data: content, mimeType },\n ];\n}\n\n/**\n * Convert an attachment DTO into MCP content blocks.\n *\n * - utf-8 text → metadata/paging header + raw text (not JSON.stringify'd —\n * that double-escapes it).\n * - base64 images → metadata header + a proper MCP image block so the model\n * actually sees the image. Dumping base64 into a text block both blows the\n * client's token limit and is unviewable.\n * - anything else → metadata JSON with `content` stripped, so inlined bytes\n * can never leak into a text block.\n */\nexport function buildAttachmentContent(file: AttachmentResult): AttachmentContentBlock[] {\n if (typeof file.content === \"string\" && file.contentEncoding === \"utf-8\") {\n return buildTextContent(file, file.content);\n }\n if (\n typeof file.content === \"string\" &&\n file.contentEncoding === \"base64\" &&\n file.mimeType?.startsWith(\"image/\")\n ) {\n return buildImageContent(file, file.content, file.mimeType);\n }\n const { content: _content, ...metadata } = file;\n return [{ type: \"text\", text: JSON.stringify(metadata, null, 2) }];\n}\n\nfunction registerGetAttachment(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"get_attachment\",\n \"Fetch one task file's content plus metadata by file ID (accepts task id or slug). Pass projectId to target a specific project; otherwise the configured default project is used. Images are returned as viewable image blocks. Large text files (logs, JSON) are returned in pages — use `offset`/`maxBytes` to read more, or fetch `downloadUrl` for the whole file. Call list_task_files first to discover IDs and sizes.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n fileId: z.string().describe(\"The file ID to fetch\"),\n offset: z\n .number()\n .int()\n .nonnegative()\n .optional()\n .describe(\"Byte offset into text content (paging). Default 0.\"),\n maxBytes: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\"Max bytes of text content to return from offset.\"),\n },\n async (params) => {\n const file = (await conn.getAttachment(params.taskId, params.fileId, {\n offset: params.offset,\n maxBytes: params.maxBytes,\n projectId: params.projectId,\n })) as AttachmentResult;\n return { content: buildAttachmentContent(file) };\n },\n );\n}\n\nfunction registerUploadAttachment(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"upload_attachment\",\n \"Upload a local file as a task attachment (any file type, up to 25MB). Pass projectId to target a specific project; otherwise the configured default project is used. The file appears under the task's Files. Pass `comment` to also post it to the task chat in the same step.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n path: z.string().describe(\"Absolute path to the local file to upload\"),\n comment: z\n .string()\n .optional()\n .describe(\"When set, also posts the attachment to the task chat with this text\"),\n mimeType: z\n .string()\n .optional()\n .describe(\"Override the mime type inferred from the file extension\"),\n },\n async (params) => {\n const info = await stat(params.path).catch(() => null);\n if (!info?.isFile()) {\n return { content: [{ type: \"text\" as const, text: `File not found: ${params.path}` }] };\n }\n if (info.size > MAX_FILE_SIZE_BYTES) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `File is ${info.size} bytes — exceeds the ${MAX_FILE_SIZE_BYTES} byte (25MB) upload limit.`,\n },\n ],\n };\n }\n\n const fileName = basename(params.path);\n const mimeType = inferMimeType(params.path, params.mimeType);\n const { fileId, uploadUrl } = await conn.requestFileUpload(params.taskId, {\n fileName,\n mimeType,\n fileSize: info.size,\n projectId: params.projectId,\n });\n\n // PUT raw bytes to the capability upload URL (the API byte-proxy streams\n // them to GCS). Content-Type carries the mime so the stored object is set.\n const body = await readFile(params.path);\n const res = await fetch(uploadUrl, {\n method: \"PUT\",\n headers: { \"Content-Type\": mimeType },\n body,\n });\n if (!res.ok) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Upload to storage failed: HTTP ${res.status} ${await res.text().catch(() => \"\")}`,\n },\n ],\n };\n }\n\n const result = await conn.confirmFileUpload(\n params.taskId,\n fileId,\n params.comment,\n params.projectId,\n );\n const lines = [\n `Uploaded ${result.fileName} (${info.size} bytes, ${mimeType}). File ID: ${result.fileId}`,\n ];\n if (result.downloadUrl) lines.push(`downloadUrl: ${result.downloadUrl}`);\n if (result.messageId) lines.push(\"Posted to the task chat.\");\n return { content: [{ type: \"text\" as const, text: lines.join(\"\\n\") }] };\n },\n );\n}\n\nexport function registerAttachmentTools(server: McpServer, conn: ConveyorConnection): void {\n registerListTaskFiles(server, conn);\n registerGetAttachment(server, conn);\n registerUploadAttachment(server, conn);\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\n\nexport function registerPullRequestTools(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"create_pull_request\",\n \"Open a GitHub pull request for a task's existing branch (the branch must already be pushed to origin). Pass projectId to target a specific project; otherwise the configured default project is used. Moves the task to ReviewPR. Returns the PR number and URL.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID whose branch should be opened as a PR\"),\n title: z.string().describe(\"Pull request title\"),\n body: z.string().describe(\"Pull request body (markdown)\"),\n head: z\n .string()\n .optional()\n .describe(\"Source branch for the PR (defaults to the task's branch)\"),\n base: z\n .string()\n .optional()\n .describe(\"Target branch for the PR (defaults to the repo default)\"),\n },\n async (params) => {\n const result = await conn.createPullRequest(params);\n return {\n content: [{ type: \"text\", text: `PR #${result.prNumber} opened: ${result.prUrl}` }],\n };\n },\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\n\nconst STATUS_ENUM = [\n \"Planning\",\n \"Open\",\n \"InProgress\",\n \"ReviewPR\",\n \"ReviewDev\",\n \"ReviewLive\",\n \"Complete\",\n \"Cancelled\",\n] as const;\n\nconst SP_DESCRIPTION = \"Story point value (1=Common, 2=Magic, 3=Rare, 5=Unique)\";\nconst FOLLOW_PARENT_STATUS_DESCRIPTION =\n \"When true, this subtask mirrors the parent task's status automatically — for children that ship on the parent's branch/PR and have no build or PR of their own. Manual status writes on a follower stick only until the parent's next transition.\";\n\nfunction registerCreateSubtask(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"create_subtask\",\n \"Create a subtask under a parent task. Pass projectId to target a specific project; otherwise the configured default project is used. Subtasks break a larger task into independently buildable pieces. For children that instead ship on the parent's own branch/PR (e.g. per-theme tracking cards for one bundled PR), set followParentStatus so their status rides the parent's automatically.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n parentTaskId: z.string().describe(\"The parent task ID\"),\n title: z.string().describe(\"Subtask title\"),\n description: z.string().optional().describe(\"Subtask description\"),\n plan: z.string().optional().describe(\"Subtask implementation plan (markdown)\"),\n ordinal: z.number().optional().describe(\"Ordering position among siblings\"),\n storyPointValue: z.number().optional().describe(SP_DESCRIPTION),\n followParentStatus: z.boolean().optional().describe(FOLLOW_PARENT_STATUS_DESCRIPTION),\n dependsOn: z\n .array(z.string())\n .optional()\n .describe(\n \"Sibling subtask ids or slugs this subtask blocks on (it won't start until they merge to dev). Set explicit dependency metadata here instead of describing order in the plan text. Omit / leave empty for independent children so they run in parallel.\",\n ),\n },\n async (params) => {\n const subtask = await conn.createSubtask(params);\n return {\n content: [{ type: \"text\", text: `Subtask created: ${subtask.id} (slug: ${subtask.slug})` }],\n };\n },\n );\n}\n\nfunction registerUpdateSubtask(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"update_subtask\",\n \"Update a subtask's fields: title, description, plan, status, ordering, or story points. Pass projectId to target a specific project; otherwise the configured default project is used. Moving a subtask beyond Planning auto-fills missing story points and agent assignment — don't spend turns on them.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n subtaskId: z.string().describe(\"The subtask ID\"),\n title: z.string().optional().describe(\"New title\"),\n description: z.string().optional().describe(\"New description\"),\n plan: z.string().optional().describe(\"New plan (markdown)\"),\n status: z.enum(STATUS_ENUM).optional().describe(\"New status\"),\n ordinal: z.number().optional().describe(\"New ordering position among siblings\"),\n storyPointValue: z.number().optional().describe(SP_DESCRIPTION),\n followParentStatus: z.boolean().optional().describe(FOLLOW_PARENT_STATUS_DESCRIPTION),\n },\n async (params) => {\n const result = await conn.updateSubtask(params);\n return {\n content: [\n { type: \"text\", text: `Subtask ${result.id} updated (status: ${result.status})` },\n ],\n };\n },\n );\n}\n\nfunction registerListSubtasks(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"list_subtasks\",\n \"List all subtasks of a parent task with their status and ordering. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The parent task ID\"),\n },\n async (params) => {\n const subtasks = await conn.listSubtasks(params.taskId, params.projectId);\n return { content: [{ type: \"text\", text: JSON.stringify(subtasks, null, 2) }] };\n },\n );\n}\n\nfunction registerDeleteSubtask(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"delete_subtask\",\n \"Delete a subtask by ID. Pass projectId to target a specific project; otherwise the configured default project is used. This is permanent — use update_subtask to set status to Cancelled if you only want to close it.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n subtaskId: z.string().describe(\"The subtask ID to delete\"),\n },\n async (params) => {\n const result = await conn.deleteSubtask(params.subtaskId, params.projectId);\n return {\n content: [\n { type: \"text\", text: result.deleted ? \"Subtask deleted\" : \"Subtask not deleted\" },\n ],\n };\n },\n );\n}\n\nexport function registerSubtaskTools(server: McpServer, conn: ConveyorConnection): void {\n registerCreateSubtask(server, conn);\n registerUpdateSubtask(server, conn);\n registerListSubtasks(server, conn);\n registerDeleteSubtask(server, conn);\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\n\nfunction registerGetDependencies(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"get_dependencies\",\n \"Get a task's dependencies and their met/unmet status (met = merged to dev). Pass projectId to target a specific project; otherwise the configured default project is used. Use to confirm blockers merged, or see why a task cannot start. For task state use get_task.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n },\n async (params) => {\n const deps = await conn.getDependencies(params.taskId, params.projectId);\n return { content: [{ type: \"text\", text: JSON.stringify(deps, null, 2) }] };\n },\n );\n}\n\nfunction registerAddDependency(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"add_dependency\",\n \"Add a blocking dependency — this task cannot start until the named task is merged to dev. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID that will be blocked\"),\n dependsOnSlugOrId: z.string().describe(\"Slug or ID of the task this one depends on\"),\n },\n async (params) => {\n await conn.addDependency(params);\n return { content: [{ type: \"text\", text: \"Dependency added\" }] };\n },\n );\n}\n\nfunction registerRemoveDependency(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"remove_dependency\",\n \"Remove a previously added dependency from a task. Pass projectId to target a specific project; otherwise the configured default project is used. The task is no longer blocked by the named task. Returns: confirmation string.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID to unblock\"),\n dependsOnSlugOrId: z.string().describe(\"Slug or ID of the dependency to remove\"),\n },\n async (params) => {\n await conn.removeDependency(params);\n return { content: [{ type: \"text\", text: \"Dependency removed\" }] };\n },\n );\n}\n\nexport function registerDependencyTools(server: McpServer, conn: ConveyorConnection): void {\n registerGetDependencies(server, conn);\n registerAddDependency(server, conn);\n registerRemoveDependency(server, conn);\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\n\nexport function registerSuggestionTools(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"create_suggestion\",\n \"Suggest a feature, improvement, rule, or idea for the project. Pass projectId to target a specific project; otherwise the configured default project is used. Duplicates are deduped and your upvote is recorded.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n title: z.string().describe(\"Suggestion title\"),\n description: z.string().optional().describe(\"Suggestion details (markdown)\"),\n tagNames: z\n .array(z.string())\n .optional()\n .describe('Tag names to categorize the suggestion (e.g., [\"agent-runner\"])'),\n },\n async (params) => {\n const result = await conn.createSuggestion(params);\n const text = result.merged\n ? `Suggestion merged into existing suggestion ${result.mergedIntoId} (upvote recorded)`\n : `Suggestion created: ${result.id}`;\n return { content: [{ type: \"text\", text }] };\n },\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\n\ntype ManualTestGroup = Awaited<ReturnType<ConveyorConnection[\"queryManualTests\"]>>[number];\n\n/** Compact grouped rendering for cross-task manual-test queries: one header per\n * task, one line per test with a status glyph, and the failing reason indented\n * under each rejected test. */\nfunction renderManualTestGroups(groups: ManualTestGroup[]): string {\n const lines: string[] = [];\n for (const g of groups) {\n lines.push(`## ${g.title} [${g.status}] (${g.slug})`);\n for (const t of g.tests) {\n const mark = t.status === \"approved\" ? \"✓\" : t.status === \"rejected\" ? \"✗\" : \"○\";\n lines.push(` ${mark} ${t.title} — ${t.status}`);\n if (t.status === \"rejected\") {\n for (const f of t.failures) {\n lines.push(` ⚠ ${f.userName ?? \"Someone\"}: ${f.reason ?? \"(no message)\"}`);\n }\n }\n }\n lines.push(\"\");\n }\n return lines.join(\"\\n\").trimEnd();\n}\n\nfunction registerListManualTests(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"list_manual_tests\",\n \"List the manual test checklist items for a task. Pass projectId to target a specific project; otherwise the configured default project is used. Use to see what manual verification steps have already been recorded.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug (the value in a card URL, /cards/<slug>)\"),\n },\n async (params) => {\n const items = await conn.listManualTests(params.taskId, params.projectId);\n if (items.length === 0) {\n return { content: [{ type: \"text\", text: \"No manual tests recorded for this task.\" }] };\n }\n const lines = items.flatMap((item, i) => {\n const checked = item.checked ? \"[x]\" : \"[ ]\";\n const row = [`${i + 1}. ${checked} ${item.title}`];\n for (const f of item.failures ?? []) {\n const who = f.userName ?? \"Someone\";\n const reason = f.reason ?? \"(no message)\";\n row.push(` ⚠ Failed (${who}): ${reason}`);\n }\n return row;\n });\n return { content: [{ type: \"text\", text: lines.join(\"\\n\") }] };\n },\n );\n}\n\nfunction registerSetManualTests(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"set_manual_tests\",\n \"Add manual test steps to a task's checklist. Pass projectId to target a specific project; otherwise the configured default project is used. Existing items with the same title are automatically skipped (deduplication). Use to record specific manual verification steps that reviewers should follow when testing the task's PR.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n items: z\n .array(z.object({ title: z.string().min(1).describe(\"A concise, actionable test step\") }))\n .min(1)\n .describe(\"List of manual test steps to add\"),\n },\n async (params) => {\n const result = await conn.setManualTests(params.taskId, params.items, params.projectId);\n const parts = [`Created ${result.created} manual test item(s).`];\n if (result.skipped > 0) parts.push(`Skipped ${result.skipped} duplicate(s).`);\n return { content: [{ type: \"text\", text: parts.join(\" \") }] };\n },\n );\n}\n\nfunction registerEditManualTest(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"edit_manual_test\",\n \"Rename an existing manual test step on a task. Pass projectId to target a specific project; otherwise the configured default project is used. Identify the test by its current title (case-insensitive) and pass the new title to replace it.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n title: z.string().min(1).describe(\"The current title of the manual test to edit\"),\n newTitle: z.string().min(1).describe(\"The new title for the manual test\"),\n },\n async (params) => {\n await conn.editManualTest(params.taskId, params.title, params.newTitle, params.projectId);\n return { content: [{ type: \"text\", text: `Updated manual test to \"${params.newTitle}\".` }] };\n },\n );\n}\n\nfunction registerRemoveManualTest(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"remove_manual_test\",\n \"Remove an existing manual test step from a task's checklist. Pass projectId to target a specific project; otherwise the configured default project is used. Identify the test by its title (case-insensitive).\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n title: z.string().min(1).describe(\"The title of the manual test to remove\"),\n },\n async (params) => {\n await conn.removeManualTest(params.taskId, params.title, params.projectId);\n return { content: [{ type: \"text\", text: `Removed manual test \"${params.title}\".` }] };\n },\n );\n}\n\nfunction registerApproveManualTest(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"approve_manual_test\",\n \"Sign off on (approve) a manual test step on a task on behalf of your authenticated user. Pass projectId to target a specific project; otherwise the configured default project is used. Identify the test by its title (case-insensitive). Use after you have verified the step passes.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n title: z.string().min(1).describe(\"The title of the manual test to approve\"),\n },\n async (params) => {\n await conn.approveManualTest(params.taskId, params.title, params.projectId);\n return { content: [{ type: \"text\", text: `Approved manual test \"${params.title}\".` }] };\n },\n );\n}\n\nfunction registerRejectManualTest(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"reject_manual_test\",\n \"Flag an issue with (reject) a manual test step on a task on behalf of your authenticated user, recording the reason. Pass projectId to target a specific project; otherwise the configured default project is used. Identify the test by its title (case-insensitive). Use when the step fails verification.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n title: z.string().min(1).describe(\"The title of the manual test to reject\"),\n reason: z\n .string()\n .min(1)\n .max(2000)\n .describe(\"Why the test failed — what went wrong, shown to the team\"),\n },\n async (params) => {\n await conn.rejectManualTest(params.taskId, params.title, params.reason, params.projectId);\n return {\n content: [\n {\n type: \"text\",\n text: `Flagged an issue with manual test \"${params.title}\": ${params.reason}`,\n },\n ],\n };\n },\n );\n}\n\nfunction registerQueryManualTests(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"query_manual_tests\",\n \"Query manual tests across many tasks in a project, grouped by task. Filter by card status (e.g. ReviewDev, ReviewLive, Complete) and/or test status (open | approved | rejected). Use to answer questions like 'show all OPEN manual tests in ReviewDev' or 'show all REJECTED manual tests in ReviewDev/ReviewLive with the failing reason'. With no filters it defaults to the needs-attention view: open+rejected tests on ReviewDev/ReviewLive cards. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n cardStatuses: z\n .array(z.string())\n .optional()\n .describe('Filter tasks by card/column status, e.g. [\"ReviewDev\", \"ReviewLive\"]'),\n testStatuses: z\n .array(z.enum([\"open\", \"approved\", \"rejected\"]))\n .optional()\n .describe(\"Filter tests by status: open | approved | rejected\"),\n },\n async (params) => {\n const groups = await conn.queryManualTests({\n projectId: params.projectId,\n cardStatuses: params.cardStatuses,\n testStatuses: params.testStatuses,\n });\n if (groups.length === 0) {\n return { content: [{ type: \"text\", text: \"No manual tests match those filters.\" }] };\n }\n return { content: [{ type: \"text\", text: renderManualTestGroups(groups) }] };\n },\n );\n}\n\nexport function registerChecklistTools(server: McpServer, conn: ConveyorConnection): void {\n registerListManualTests(server, conn);\n registerQueryManualTests(server, conn);\n registerSetManualTests(server, conn);\n registerEditManualTest(server, conn);\n registerRemoveManualTest(server, conn);\n registerApproveManualTest(server, conn);\n registerRejectManualTest(server, conn);\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\nimport {\n startWorkspaceSshTunnel,\n type WorkspaceSshTunnelHandle,\n type WorkspaceSshTunnelOptions,\n} from \"../workspace-ssh-tunnel.js\";\n\ninterface WorkspaceToolDeps {\n startTunnel?: (options: WorkspaceSshTunnelOptions) => Promise<WorkspaceSshTunnelHandle>;\n}\n\nconst activeTunnels = new Map<string, WorkspaceSshTunnelHandle>();\n\nfunction createTunnelId(taskId: string, port: number): string {\n return `${taskId}:${port}:${Date.now().toString(36)}:${Math.random().toString(36).slice(2, 8)}`;\n}\n\nfunction localUrlFor(port: number, host: string, localPort: number): string | undefined {\n if (port === 2222) return undefined;\n return `http://${host}:${localPort}`;\n}\n\nfunction registerAttachInfoTool(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"workspace_attach_info\",\n \"Return SSH/SFTP attach metadata for a running task Claudespace, plus hosted preview URLs and configured preview ports. Optionally installs an OpenSSH public key for this attach session.\",\n {\n taskId: z.string().describe(\"The task ID\"),\n sshPublicKey: z\n .string()\n .optional()\n .describe(\"Optional OpenSSH public key to install into the workspace\"),\n },\n async ({ taskId, sshPublicKey }) => {\n const info = await conn.getWorkspaceAttachInfo(taskId, sshPublicKey);\n return { content: [{ type: \"text\", text: JSON.stringify(info, null, 2) }] };\n },\n );\n}\n\nfunction registerPreviewUrlsTool(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"workspace_preview_urls\",\n \"Return the hosted preview URLs and preview ports for a running task Claudespace. This mirrors the web UI preview link metadata.\",\n {\n taskId: z.string().describe(\"The task ID\"),\n },\n async ({ taskId }) => {\n const info = await conn.getWorkspaceAttachInfo(taskId);\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n {\n taskId: info.taskId,\n sessionId: info.sessionId,\n previewPorts: info.previewPorts,\n previewUrls: info.previewUrls,\n },\n null,\n 2,\n ),\n },\n ],\n };\n },\n );\n}\n\nfunction registerStartTunnelTool(\n server: McpServer,\n conn: ConveyorConnection,\n startTunnel: (options: WorkspaceSshTunnelOptions) => Promise<WorkspaceSshTunnelHandle>,\n): void {\n server.tool(\n \"workspace_start_tunnel\",\n \"Start a local loopback tunnel through the MCP server to a running task Claudespace port. Use port 2222 for SSH/SFTP, or one of previewPorts for app access.\",\n {\n taskId: z.string().describe(\"The task ID\"),\n port: z.number().optional().describe(\"Remote Claudespace port. Defaults to SSH port 2222.\"),\n preferredLocalPort: z\n .number()\n .optional()\n .describe(\"Preferred local loopback port. If omitted, the OS chooses one.\"),\n sshPublicKey: z\n .string()\n .optional()\n .describe(\"Optional OpenSSH public key to install before opening the tunnel\"),\n },\n async ({ taskId, port, preferredLocalPort, sshPublicKey }) => {\n const info = await conn.getWorkspaceAttachInfo(taskId, sshPublicKey);\n const remotePort = port ?? info.ssh?.remotePort ?? 2222;\n const handle = await startTunnel({\n remotePort,\n preferredLocalPort,\n // Re-mint per connection so the tunnel outlives the attach-token TTL.\n // The key (if any) is already installed by the call above; the refetch\n // only needs a fresh token, so it omits sshPublicKey.\n resolveTarget: async () => {\n const fresh = await conn.getWorkspaceAttachInfo(taskId);\n return { tunnelUrl: fresh.tunnelUrl, attachToken: fresh.attachToken };\n },\n });\n const tunnelId = createTunnelId(taskId, remotePort);\n activeTunnels.set(tunnelId, handle);\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n {\n tunnelId,\n taskId,\n remotePort,\n localHost: handle.host,\n localPort: handle.port,\n localUrl: localUrlFor(remotePort, handle.host, handle.port),\n // `-o ServerAliveInterval=30` drives client-side keepalives so an\n // idle session keeps the tunnel warm (the tunnel layer pings too,\n // but the client must keep its own TCP path alive across every hop).\n sshCommand:\n remotePort === 2222\n ? `ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -p ${handle.port} ${info.ssh?.username ?? \"conveyor\"}@${handle.host}`\n : undefined,\n sftpCommand:\n remotePort === 2222\n ? `sftp -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -P ${handle.port} ${info.ssh?.username ?? \"conveyor\"}@${handle.host}`\n : undefined,\n previewPorts: info.previewPorts,\n previewUrls: info.previewUrls,\n expiresAt: info.expiresAt,\n },\n null,\n 2,\n ),\n },\n ],\n };\n },\n );\n}\n\nfunction registerStopTunnelTool(server: McpServer): void {\n server.tool(\n \"workspace_stop_tunnel\",\n \"Stop a local workspace tunnel previously opened by workspace_start_tunnel.\",\n {\n tunnelId: z.string().describe(\"Tunnel id returned by workspace_start_tunnel\"),\n },\n async ({ tunnelId }) => {\n const tunnel = activeTunnels.get(tunnelId);\n if (!tunnel) throw new Error(\"Workspace tunnel not found\");\n await tunnel.close();\n activeTunnels.delete(tunnelId);\n return { content: [{ type: \"text\", text: \"Workspace tunnel stopped\" }] };\n },\n );\n}\n\nexport function registerWorkspaceTools(\n server: McpServer,\n conn: ConveyorConnection,\n deps: WorkspaceToolDeps = {},\n): void {\n registerAttachInfoTool(server, conn);\n registerPreviewUrlsTool(server, conn);\n registerStartTunnelTool(server, conn, deps.startTunnel ?? startWorkspaceSshTunnel);\n registerStopTunnelTool(server);\n}\n","import net from \"node:net\";\nimport { once } from \"node:events\";\nimport { WebSocket } from \"ws\";\n\n// Mirrors WORKSPACE_TUNNEL_HEARTBEAT_MS in @project/shared constants/workspace-tunnel.ts\n// (conveyor-mcp has no workspace dependencies — the two tunnel ends share this\n// value by convention). Cloudflare reaps idle proxied WebSockets, so both ends\n// ping on this interval to keep the edge connection warm.\nconst WORKSPACE_TUNNEL_HEARTBEAT_MS = 30_000;\n\nexport interface WorkspaceTunnelTarget {\n tunnelUrl: string;\n attachToken: string;\n}\n\nexport interface WorkspaceSshTunnelOptions {\n // Minted fresh for every local connection so long-lived clients (VS Code\n // Remote-SSH / SSHFS open many short connections over one session) keep\n // working after the short-lived attach token expires — no refresh plumbing,\n // just re-fetch on connect.\n resolveTarget: () => Promise<WorkspaceTunnelTarget>;\n remotePort: number;\n preferredLocalPort?: number;\n host?: string;\n}\n\nexport interface WorkspaceSshTunnelHandle {\n host: string;\n port: number;\n close: () => Promise<void>;\n}\n\nfunction withPort(url: string, port: number): string {\n const parsed = new URL(url);\n parsed.searchParams.set(\"port\", String(port));\n return parsed.toString();\n}\n\nfunction toBuffer(data: WebSocket.RawData): Buffer {\n if (Buffer.isBuffer(data)) return data;\n if (data instanceof ArrayBuffer) return Buffer.from(data);\n return Buffer.concat(data);\n}\n\n// Ping from this end too: a long-lived single connection (interactive `ssh`,\n// `ssh -L` forward) carries no traffic while idle, and Cloudflare reaps idle\n// proxied WebSockets. The heartbeat keeps the upstream warm so the tunnel\n// lives as long as the workspace, not just until the next idle reap.\nfunction startHeartbeat(ws: WebSocket): () => void {\n const timer = setInterval(() => {\n if (ws.readyState === WebSocket.OPEN) ws.ping();\n }, WORKSPACE_TUNNEL_HEARTBEAT_MS);\n timer.unref?.();\n return () => clearInterval(timer);\n}\n\n// Bridge one accepted local connection (ssh/sftp) to a freshly-minted upstream\n// WebSocket. Each local connection re-mints via `resolveTarget`, so long-lived\n// clients keep working past the attach-token TTL.\nfunction bridgeClient(client: net.Socket, options: WorkspaceSshTunnelOptions): void {\n let ws: WebSocket | null = null;\n let ready = false;\n // Client (ssh) bytes can arrive before the async re-mint + WS open; hold\n // them until the upstream is ready so the handshake isn't dropped.\n const pending: Buffer[] = [];\n client.on(\"data\", (chunk) => {\n if (ready && ws && ws.readyState === WebSocket.OPEN) ws.send(chunk);\n else pending.push(chunk);\n });\n client.on(\"close\", () => ws?.close());\n client.on(\"error\", () => ws?.close());\n\n options\n .resolveTarget()\n .then(({ tunnelUrl, attachToken }) => {\n // Token rides in a header, not the query string, so it isn't captured\n // by edge/proxy access logs. (Node `ws` can set request headers; the\n // browser WebSocket API can't — but this client is always Node.)\n const socket = new WebSocket(withPort(tunnelUrl, options.remotePort), {\n headers: { \"x-workspace-attach-token\": attachToken },\n });\n ws = socket;\n const stopHeartbeat = startHeartbeat(socket);\n socket.on(\"message\", (data) => {\n const chunk = toBuffer(data);\n if (!ready) {\n const text = chunk.toString(\"utf8\");\n if (text === JSON.stringify({ ok: true })) {\n ready = true;\n for (const buffered of pending.splice(0)) socket.send(buffered);\n return;\n }\n client.destroy(new Error(`Workspace tunnel rejected connection: ${text}`));\n socket.close();\n return;\n }\n client.write(chunk);\n });\n socket.on(\"close\", () => {\n stopHeartbeat();\n client.destroy();\n });\n socket.on(\"error\", (err) => {\n stopHeartbeat();\n client.destroy(err);\n });\n })\n .catch((err) => {\n client.destroy(err instanceof Error ? err : new Error(String(err)));\n });\n}\n\nexport async function startWorkspaceSshTunnel(\n options: WorkspaceSshTunnelOptions,\n): Promise<WorkspaceSshTunnelHandle> {\n const host = options.host ?? \"127.0.0.1\";\n const server = net.createServer((client) => bridgeClient(client, options));\n\n // Race \"listening\" against \"error\": a busy preferredLocalPort emits \"error\"\n // with no listener, which would otherwise crash the MCP process.\n const ac = new AbortController();\n server.listen(options.preferredLocalPort ?? 0, host);\n try {\n await Promise.race([\n once(server, \"listening\", { signal: ac.signal }),\n once(server, \"error\", { signal: ac.signal }).then(([err]) => {\n throw err instanceof Error ? err : new Error(String(err));\n }),\n ]);\n } catch (err) {\n server.close();\n throw new Error(\n `Failed to bind workspace SSH tunnel: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err },\n );\n } finally {\n ac.abort();\n }\n const address = server.address();\n if (!address || typeof address === \"string\") {\n server.close();\n throw new Error(\"Failed to bind workspace SSH tunnel\");\n }\n\n return {\n host,\n port: address.port,\n close: () =>\n new Promise<void>((resolve, reject) => {\n server.close((err) => {\n if (err) reject(err);\n else resolve();\n });\n }),\n };\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection, GcpLogEntry } from \"../connection.js\";\n\nconst SEVERITY_ENUM = [\n \"DEBUG\",\n \"INFO\",\n \"NOTICE\",\n \"WARNING\",\n \"ERROR\",\n \"CRITICAL\",\n \"ALERT\",\n \"EMERGENCY\",\n] as const;\n\nconst MAX_LINE_CHARS = 400;\nconst DEFAULT_SINCE_MINUTES = 60;\n\nfunction truncateLine(text: string): string {\n const oneLine = text.replace(/\\s*\\n\\s*/g, \" ⏎ \");\n if (oneLine.length <= MAX_LINE_CHARS) return oneLine;\n const overflow = oneLine.length - MAX_LINE_CHARS;\n return `${oneLine.slice(0, MAX_LINE_CHARS)}…[+${overflow}c]`;\n}\n\nfunction entrySource(entry: GcpLogEntry): string {\n return (\n entry.resource.service_name ??\n entry.resource.pod_name ??\n entry.resource.database_id ??\n entry.resourceType ??\n \"-\"\n );\n}\n\nexport function formatLogEntryLine(entry: GcpLogEntry): string {\n const httpPrefix = entry.httpRequest?.status\n ? `http ${entry.httpRequest.status} ${entry.httpRequest.method ?? \"\"} ${entry.httpRequest.url ?? \"\"}`.trim() +\n \" — \"\n : \"\";\n return `${entry.timestamp} ${entry.severity.padEnd(7)} [${entrySource(entry)}] ${truncateLine(\n `${httpPrefix}${entry.message}`,\n )}`;\n}\n\nexport interface QueryGcpLogsToolParams {\n projectId?: string;\n env?: \"prod\" | \"dev\" | \"claudespace\";\n sinceMinutes?: number;\n startTime?: string;\n endTime?: string;\n severity?: (typeof SEVERITY_ENUM)[number];\n services?: string[];\n sqlInstances?: string[];\n allServices?: boolean;\n search?: string;\n filter?: string;\n limit?: number;\n pageToken?: string;\n}\n\n/** Exported for tests — the tool handler minus MCP plumbing. */\nexport async function runQueryGcpLogs(\n conn: ConveyorConnection,\n params: QueryGcpLogsToolParams,\n now: () => number = Date.now,\n): Promise<string> {\n const startTime =\n params.startTime ??\n new Date(now() - (params.sinceMinutes ?? DEFAULT_SINCE_MINUTES) * 60_000).toISOString();\n\n const result = await conn.queryGcpLogs({\n projectId: params.projectId,\n env: params.env,\n severity: params.severity,\n services: params.services,\n sqlInstances: params.sqlInstances,\n allServices: params.allServices,\n search: params.search,\n filter: params.filter,\n startTime,\n endTime: params.endTime,\n limit: params.limit,\n pageToken: params.pageToken,\n });\n\n if (result.error) return result.error;\n\n const header = [\n `env=${params.env ?? \"prod\"}`,\n `window=${startTime}→${params.endTime ?? \"now\"}`,\n ...(params.severity ? [`minSeverity=${params.severity}`] : []),\n `scope=${result.scopedServices ? `[${result.scopedServices.join(\", \")}]` : \"all\"}`,\n `entries=${result.entries.length}`,\n ].join(\" \");\n\n const lines = result.entries.map(formatLogEntryLine);\n const footer = result.nextPageToken\n ? [`-- more available: pass pageToken=\"${result.nextPageToken}\" to continue`]\n : [];\n\n if (lines.length === 0) {\n return [\n header,\n \"(no matching log entries — widen the window, lower minSeverity, or drop filters)\",\n ].join(\"\\n\");\n }\n return [header, ...lines, ...footer].join(\"\\n\");\n}\n\nexport function registerLogTools(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"query_gcp_logs\",\n \"Query Google Cloud Logging for a project's linked GCP environments — use this to investigate production or dev issues directly ('something broke on prod'). Envs: 'prod' and 'dev' are the project's Cloud Run apps + Cloud SQL databases (scoped by default to the resources linked in project settings); 'claudespace' is the project's GKE agent-pod namespace. Start broad (severity=ERROR, sinceMinutes=60), then narrow with services/search. Returns compact lines: '<time> <SEVERITY> [<source>] <message>'. When the response ends with a pageToken line, pass that token back as pageToken for the next page. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n env: z\n .enum([\"prod\", \"dev\", \"claudespace\"])\n .optional()\n .describe(\"GCP environment slot to query (default prod)\"),\n sinceMinutes: z\n .number()\n .int()\n .min(1)\n .max(10080)\n .optional()\n .describe(\n \"Relative time window ending now, in minutes (default 60). Ignored if startTime is set.\",\n ),\n startTime: z.string().optional().describe(\"ISO 8601 lower bound (overrides sinceMinutes)\"),\n endTime: z.string().optional().describe(\"ISO 8601 upper bound (default now)\"),\n severity: z\n .enum(SEVERITY_ENUM)\n .optional()\n .describe(\"Minimum severity, inclusive — ERROR returns ERROR and above\"),\n services: z\n .array(z.string())\n .optional()\n .describe(\n \"Restrict to these Cloud Run service names (prod/dev only). Defaults to all services linked in project settings.\",\n ),\n sqlInstances: z\n .array(z.string())\n .optional()\n .describe(\"Restrict to these Cloud SQL instance names (prod/dev only)\"),\n allServices: z\n .boolean()\n .optional()\n .describe(\n \"Set true to search ALL logs in the GCP project, ignoring the linked-resource scope\",\n ),\n search: z\n .string()\n .max(256)\n .optional()\n .describe(\"Free-text search across all log fields (exact substring, not regex)\"),\n filter: z\n .string()\n .max(1000)\n .optional()\n .describe(\"Advanced: raw Cloud Logging filter expression, ANDed with the scope\"),\n limit: z\n .number()\n .int()\n .min(1)\n .max(200)\n .optional()\n .describe(\"Max entries per page (default 50)\"),\n pageToken: z\n .string()\n .optional()\n .describe(\"Opaque token from a previous response to fetch the next page\"),\n },\n async (params) => {\n const text = await runQueryGcpLogs(conn, params);\n return { content: [{ type: \"text\", text }] };\n },\n );\n}\n","/* oxlint-disable import/max-dependencies -- registration aggregator imports every tool module by design */\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\nimport { registerProjectTools } from \"./project.js\";\nimport { registerTaskTools } from \"./tasks.js\";\nimport { registerBuildTools } from \"./builds.js\";\nimport { registerAttachmentTools } from \"./attachments.js\";\nimport { registerPullRequestTools } from \"./pull-request.js\";\nimport { registerSubtaskTools } from \"./subtasks.js\";\nimport { registerDependencyTools } from \"./dependencies.js\";\nimport { registerSuggestionTools } from \"./suggestions.js\";\nimport { registerChecklistTools } from \"./checklists.js\";\nimport { registerWorkspaceTools } from \"./workspace.js\";\nimport { registerLogTools } from \"./logs.js\";\n\nexport function registerAllTools(server: McpServer, conn: ConveyorConnection): void {\n registerProjectTools(server, conn);\n registerTaskTools(server, conn);\n registerBuildTools(server, conn);\n registerAttachmentTools(server, conn);\n registerPullRequestTools(server, conn);\n registerSubtaskTools(server, conn);\n registerDependencyTools(server, conn);\n registerSuggestionTools(server, conn);\n registerChecklistTools(server, conn);\n registerWorkspaceTools(server, conn);\n registerLogTools(server, conn);\n}\n"],"mappings":"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","names":["server","conn","z","server","conn","projectId","z","server","conn","z","server","conn","z","server","conn","z","STATUS_ENUM","server","conn","z","server","conn","z","server","conn","z","server","conn","z","server","server","conn","z","z","conn","server","server","conn"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/tools/project.ts","../src/tools/tasks.ts","../src/tools/builds.ts","../src/tools/attachments.ts","../src/tools/pull-request.ts","../src/tools/subtasks.ts","../src/tools/dependencies.ts","../src/tools/suggestions.ts","../src/tools/checklists.ts","../src/tools/workspace.ts","../src/workspace-ssh-tunnel.ts","../src/tools/logs.ts","../src/tools/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { createRequire } from \"node:module\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { ConveyorConnection } from \"./connection.js\";\nimport { registerAllTools } from \"./tools/index.js\";\n\nconst { version } = createRequire(import.meta.url)(\"../package.json\") as { version: string };\n\nconst apiUrl = process.env.CONVEYOR_API_URL;\nconst projectToken = process.env.CONVEYOR_USER_TOKEN ?? process.env.CONVEYOR_PROJECT_TOKEN;\nconst projectId = process.env.CONVEYOR_PROJECT_ID;\n\nif (!apiUrl || !projectToken) {\n process.stderr.write(\n \"Error: CONVEYOR_API_URL and CONVEYOR_USER_TOKEN or CONVEYOR_PROJECT_TOKEN environment variables are required. CONVEYOR_PROJECT_ID is optional and sets the default project.\\n\",\n );\n process.exit(1);\n}\n\nconst conn = new ConveyorConnection({ apiUrl, projectToken, projectId });\n\ntry {\n await conn.connect();\n process.stderr.write(\"Connected to Conveyor API\\n\");\n} catch (err) {\n process.stderr.write(`Failed to connect to Conveyor API: ${err}\\n`);\n process.exit(1);\n}\n\nconst server = new McpServer({\n name: \"conveyor\",\n version,\n});\n\nregisterAllTools(server, conn);\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n\nprocess.on(\"SIGINT\", () => {\n conn.disconnect();\n process.exit(0);\n});\n\nprocess.on(\"SIGTERM\", () => {\n conn.disconnect();\n process.exit(0);\n});\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\n\nexport function registerProjectTools(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"list_projects\",\n \"List Conveyor projects available to this MCP token's user. Use a returned project id as projectId on other tools when no default project is configured or when targeting a different project.\",\n {},\n async () => {\n const projects = await conn.listProjects();\n return { content: [{ type: \"text\", text: JSON.stringify(projects, null, 2) }] };\n },\n );\n\n server.tool(\n \"get_project_summary\",\n \"Get overall project status: task counts by status, active builds, repo info. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n },\n async (params) => {\n const summary = await conn.getProjectSummary(params.projectId);\n return { content: [{ type: \"text\", text: JSON.stringify(summary, null, 2) }] };\n },\n );\n\n server.tool(\n \"list_project_members\",\n \"List project members with user ID, name, email, and access level — use to resolve a person's name or email to a user ID for task assignment or review. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n },\n async (params) => {\n const members = await conn.listProjectMembers(params.projectId);\n return { content: [{ type: \"text\", text: JSON.stringify(members, null, 2) }] };\n },\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\n\nconst CLI_EVENT_FORMATTERS: Record<string, (data: Record<string, unknown>) => string> = {\n thinking: (data) => String(data.message ?? \"\"),\n tool_use: (data) => `${data.tool}: ${String(data.input ?? \"\").slice(0, 1000)}`,\n tool_result: (data) =>\n `${data.tool} → ${String(data.output ?? \"\").slice(0, 500)}${data.isError ? \" [ERROR]\" : \"\"}`,\n message: (data) => String(data.content ?? \"\"),\n error: (data) => `ERROR: ${String(data.message ?? \"\")}`,\n completed: (data) =>\n `Completed: ${data.summary ?? \"\"} (cost: $${data.costUsd ?? \"?\"}, duration: ${data.durationMs ?? \"?\"}ms)`,\n setup_output: (data) => `[${data.stream ?? \"stdout\"}] ${String(data.data ?? \"\")}`,\n start_command_output: (data) => `[${data.stream ?? \"stdout\"}] ${String(data.data ?? \"\")}`,\n turn_end: (data) =>\n `Turn complete (${Array.isArray(data.toolCalls) ? data.toolCalls.length : 0} tool calls)`,\n};\n\nfunction formatCliEventSummary(type: string, data: Record<string, unknown>): string {\n const formatter = CLI_EVENT_FORMATTERS[type];\n return formatter ? formatter(data) : JSON.stringify(data);\n}\n\ntype TaskSessionState = Awaited<ReturnType<ConveyorConnection[\"getTaskSessions\"]>>[number];\ntype LegacyComputeSession = TaskSessionState[\"sessions\"][number];\ntype WorkspaceState = TaskSessionState[\"workspaces\"][number];\ntype WorkspaceSessionState = WorkspaceState[\"sessions\"][number];\n\nfunction formatLegacyComputeSession(s: LegacyComputeSession): string {\n return (\n ` - session ${s.id} [${s.provider}] pod=${s.instanceName ?? \"-\"} status=${s.status}` +\n ` runner=${s.agentRunnerStatus ?? \"-\"} lastHeartbeat=${s.lastHeartbeatAt ?? \"-\"}` +\n ` created=${s.createdAt} stopped=${s.stoppedAt ?? \"-\"}` +\n (s.deletionRequestedAt\n ? ` deletionRequested=${s.deletionRequestedAt} (attempts ${s.deletionAttempts})`\n : \"\") +\n (s.lastAgentEvent ? ` lastAgentEvent=${s.lastAgentEvent}` : \"\")\n );\n}\n\nfunction formatWorkspaceSession(s: WorkspaceSessionState): string {\n return (\n ` - workspaceSession ${s.id} role=${s.role} mode=${s.mode}` +\n ` status=${s.status} leaseUntil=${s.leaseUntil ?? \"-\"} created=${s.createdAt}`\n );\n}\n\nfunction formatWorkspace(w: WorkspaceState): string[] {\n const lines = [\n ` - workspace ${w.id} purpose=${w.purpose} desired=${w.desiredState}` +\n ` observed=${w.observedState} branch=${w.branch ?? \"-\"} checkoutRef=${w.checkoutRef ?? \"-\"}` +\n (w.pod ? ` pod=${w.pod.namespace}/${w.pod.name} podPhase=${w.pod.phase}` : \" pod=-\"),\n ];\n if (w.sessions.length === 0) {\n lines.push(\" (no workspace sessions)\");\n return lines;\n }\n lines.push(...w.sessions.map(formatWorkspaceSession));\n return lines;\n}\n\nfunction formatTaskSessionState(t: TaskSessionState): string[] {\n const review = t.codeReviewStatus\n ? ` codeReview=${t.codeReviewStatus} (attempts ${t.codeReviewAttempts})`\n : \"\";\n const kind = t.reviewTargetTaskId ? `review card for ${t.reviewTargetTaskId}` : t.type;\n const lines = [`# ${t.slug} — ${t.title} [${kind}, status ${t.status}]${review}`];\n if (t.sessions.length === 0) {\n lines.push(\" (no compute sessions)\");\n } else {\n lines.push(...t.sessions.map(formatLegacyComputeSession));\n }\n if (t.workspaces.length === 0) {\n lines.push(\" (no v3 workspaces)\");\n } else {\n lines.push(...t.workspaces.flatMap(formatWorkspace));\n }\n return lines;\n}\n\nconst DESCRIPTION_PREVIEW_CHARS = 300;\n\n/** List/search results omit `plan` and truncate `description` — `get_task` returns the full record. */\nfunction summarizeTask(task: unknown): unknown {\n if (typeof task !== \"object\" || task === null) return task;\n const { plan, description, ...rest } = task as Record<string, unknown>;\n const summary: Record<string, unknown> = { ...rest };\n summary.description =\n typeof description === \"string\" && description.length > DESCRIPTION_PREVIEW_CHARS\n ? `${description.slice(0, DESCRIPTION_PREVIEW_CHARS)}… [truncated — use get_task for the full description]`\n : (description ?? null);\n summary.hasPlan = typeof plan === \"string\" && plan.length > 0;\n return summary;\n}\n\nconst STATUS_ENUM = [\n \"Planning\",\n \"Open\",\n \"InProgress\",\n \"ReviewPR\",\n \"ReviewDev\",\n \"ReviewLive\",\n \"Complete\",\n \"Cancelled\",\n] as const;\n\nconst CARD_TYPE_ENUM = [\"task\", \"incident\", \"suggestion\"] as const;\n\n// Canonical risk levels — mirror RISK_LEVELS in @project/shared (conveyor-mcp is\n// published standalone without the shared dep).\nconst RISK_ENUM = [\"critical\", \"high\", \"medium\", \"low\"] as const;\n\nfunction registerListTasks(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"list_tasks\",\n \"List project tasks, optionally filtered by status or assignment (a specific assignee, or unassigned tasks). Pass projectId to target a specific project; otherwise the configured default project is used. Returns summaries — plan omitted, description truncated; use get_task for full details.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n status: z.enum(STATUS_ENUM).optional().describe(\"Filter by task status\"),\n assigneeId: z.string().optional().describe(\"Filter by assigned user ID\"),\n unassigned: z\n .boolean()\n .optional()\n .describe(\"Only return tasks with no assignee (mutually exclusive with assigneeId)\"),\n subProjectId: z\n .string()\n .optional()\n .describe(\n \"Scope to a sub-project board (list/search: filter; create/update: assign). Omit for the whole project.\",\n ),\n limit: z.number().optional().describe(\"Max tasks to return (default 50)\"),\n },\n async (params) => {\n const tasks = await conn.listTasks(params);\n return {\n content: [{ type: \"text\", text: JSON.stringify(tasks.map(summarizeTask), null, 2) }],\n };\n },\n );\n}\n\nfunction registerGetTask(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"get_task\",\n \"Get full task details including plan, chat history, PR info, subtasks, and build status. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug (the value in a card URL, /cards/<slug>)\"),\n },\n async (params) => {\n const task = await conn.getTask(params.taskId, params.projectId);\n return { content: [{ type: \"text\", text: JSON.stringify(task, null, 2) }] };\n },\n );\n}\n\nfunction registerGetCardBySlug(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"get_card_by_slug\",\n \"Get full card details by the slug from a card URL (/cards/<slug>) instead of a task ID. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n slug: z.string().describe(\"The card slug from a Conveyor card URL, e.g. 'ship-it'\"),\n },\n async (params) => {\n const task = await conn.getCardBySlug(params.slug, params.projectId);\n return { content: [{ type: \"text\", text: JSON.stringify(task, null, 2) }] };\n },\n );\n}\n\nfunction registerCreateTask(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"create_task\",\n \"Create a new task with title, description, and optional plan. Pass projectId to target a specific project; otherwise the configured default project is used. Icon, story points, and agent assignment are auto-filled when a task is created in (or later moved to) a status beyond Planning — don't spend turns on them.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n title: z.string().describe(\"Task title\"),\n description: z.string().optional().describe(\"Task description\"),\n plan: z.string().optional().describe(\"Task implementation plan (markdown)\"),\n status: z\n .enum([\"Planning\", \"Open\"])\n .optional()\n .describe(\"Initial status (default: Planning)\"),\n subProjectId: z\n .string()\n .optional()\n .describe(\n \"Scope to a sub-project board (list/search: filter; create/update: assign). Omit for the whole project.\",\n ),\n },\n async (params) => {\n const task = await conn.createTask(params);\n return {\n content: [{ type: \"text\", text: `Task created: ${task.id} (slug: ${task.slug})` }],\n };\n },\n );\n}\n\nfunction registerUpdateTask(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"update_task\",\n \"Update task fields: title, plan, risk, or assignment. Status and description are NOT editable through MCP — use approve_task / request_changes for review status moves. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n title: z.string().optional().describe(\"New title\"),\n plan: z.string().optional().describe(\"New plan (markdown)\"),\n risk: z\n .enum(RISK_ENUM)\n .nullable()\n .optional()\n .describe(\n \"Risk level — how much important surface the task touches (critical/high/medium/low). Pass null to clear.\",\n ),\n assignedUserId: z.string().nullable().optional().describe(\"User ID to assign, or null\"),\n subProjectId: z\n .string()\n .nullable()\n .optional()\n .describe(\n \"Assign the task to a sub-project board; null moves it back to the parent board. Omit to leave unchanged.\",\n ),\n },\n async (params) => {\n const result = await conn.updateTask(params);\n return {\n content: [{ type: \"text\", text: `Task ${result.id} updated (status: ${result.status})` }],\n };\n },\n );\n}\n\nfunction registerMoveCard(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"move_card\",\n \"Move an eligible Planning or Open task, incident, or suggestion card to another project. Cards with identification or automation in progress, active compute, pull requests, deployments, releases, reviews, or delivered reporter email cannot move. Project-specific metadata is cleared instead of mapped by name. Pass projectId for the source project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Source Conveyor project ID\"),\n taskId: z.string().describe(\"Card ID or slug\"),\n destinationProjectId: z.string().describe(\"Destination Conveyor project ID\"),\n },\n async (params) => {\n const result = await conn.moveCard(params);\n const clearedFields =\n result.clearedFields.length > 0 ? result.clearedFields.join(\", \") : \"none\";\n return {\n content: [\n {\n type: \"text\",\n text: `Card moved as ${result.slug} to project ${result.destinationProjectId}. Cleared fields: ${clearedFields}`,\n },\n ],\n };\n },\n );\n}\n\nfunction registerChatTools(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"read_task_chat\",\n \"Read messages from a task's chat. Pass projectId to target a specific project; otherwise the configured default project is used. For agent execution logs use get_task_logs.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n limit: z.number().optional().describe(\"Max messages to return (default 50)\"),\n },\n async (params) => {\n const messages = await conn.getTaskChat(params.taskId, params.limit, params.projectId);\n return { content: [{ type: \"text\", text: JSON.stringify(messages, null, 2) }] };\n },\n );\n\n server.tool(\n \"post_to_chat\",\n \"Post a message to a task's chat. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n content: z.string().describe(\"Message content\"),\n },\n async (params) => {\n await conn.postToTaskChat(params.taskId, params.content, params.projectId);\n return { content: [{ type: \"text\", text: \"Message posted\" }] };\n },\n );\n}\n\nfunction registerGetTaskCli(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"get_task_logs\",\n \"Read CLI execution logs from a task. Pass projectId to target a specific project; otherwise the configured default project is used. Returns agent reasoning, tool calls, setup output, and other execution events. For human chat use read_task_chat.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n source: z\n .enum([\"agent\", \"application\"])\n .optional()\n .describe(\n \"Filter by log source: 'agent' for reasoning/tool calls, 'application' for setup/dev-server output\",\n ),\n limit: z.number().optional().describe(\"Max entries to return (default 50, max 500)\"),\n },\n async ({ taskId, source, limit, projectId }) => {\n const effectiveLimit = Math.min(limit ?? 50, 500);\n const logs = await conn.getTaskCli(taskId, effectiveLimit, source, projectId);\n const formatted = logs\n .map((log) => {\n return `[${log.timestamp}] [${log.type}] ${formatCliEventSummary(log.type, log.data)}`;\n })\n .join(\"\\n\");\n return {\n content: [{ type: \"text\" as const, text: formatted || \"No CLI logs found for this task.\" }],\n };\n },\n );\n}\n\nfunction registerGetTaskSessions(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"get_task_sessions\",\n \"Read compute-session state for a task: legacy CodespaceSession rows plus v3 workspaces, including purpose=review review workspaces. Shows pod identity, liveness, lifecycle, and code-review claim state. Use to diagnose stalled/dead agents or code-review runs. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n },\n async ({ taskId, projectId }) => {\n const tasks = await conn.getTaskSessions(taskId, projectId);\n const lines = tasks.flatMap(formatTaskSessionState);\n return {\n content: [\n { type: \"text\" as const, text: lines.join(\"\\n\") || \"No sessions found for this task.\" },\n ],\n };\n },\n );\n}\n\nfunction registerSearchTasks(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"search_tasks\",\n \"Search cards by tag name, text query, status, type, and/or assignment. Defaults to type=task — pass typeFilters to include incidents/suggestions. Pass projectId to target a specific project; otherwise the configured default project is used. Use tag names like 'agent-runner', not IDs. Returns summaries — plan omitted, description truncated; use get_task for full details.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n tagNames: z\n .array(z.string())\n .optional()\n .describe('Tag names to filter by (e.g., [\"agent-runner\", \"chat\"])'),\n searchQuery: z.string().optional().describe(\"Text search on title and description\"),\n statusFilters: z\n .array(z.enum(STATUS_ENUM))\n .optional()\n .describe(\"Filter by one or more statuses\"),\n typeFilters: z\n .array(z.enum(CARD_TYPE_ENUM))\n .optional()\n .describe(\n 'Card types to include (default [\"task\"]). Pass e.g. [\"incident\"] or list several to search across types.',\n ),\n assigneeId: z.string().optional().describe(\"Filter by assigned user ID\"),\n unassigned: z\n .boolean()\n .optional()\n .describe(\"Only return tasks with no assignee (mutually exclusive with assigneeId)\"),\n subProjectId: z\n .string()\n .optional()\n .describe(\n \"Scope to a sub-project board (list/search: filter; create/update: assign). Omit for the whole project.\",\n ),\n limit: z.number().optional().describe(\"Max results to return (default 20)\"),\n },\n async (params) => {\n const tasks = await conn.searchTasks(params);\n return {\n content: [{ type: \"text\", text: JSON.stringify(tasks.map(summarizeTask), null, 2) }],\n };\n },\n );\n}\n\nfunction registerListTags(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"list_tags\",\n \"List all project tags with their names, IDs, and colors. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n },\n async (params) => {\n const tags = await conn.listTags(params.projectId);\n return { content: [{ type: \"text\", text: JSON.stringify(tags, null, 2) }] };\n },\n );\n}\n\nfunction registerReviewTools(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"approve_task\",\n \"Move a task forward in the review flow (ReviewPR -> ReviewDev, or -> Complete). Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n risk: z\n .enum(RISK_ENUM)\n .optional()\n .describe(\"Optional risk level to record; defaults to a raise-only 'low' on approval.\"),\n },\n async (params) => {\n const result = await conn.approveTask(params.taskId, params.projectId, params.risk);\n return {\n content: [{ type: \"text\", text: `Task approved, new status: ${result.status}` }],\n };\n },\n );\n\n server.tool(\n \"approve_and_merge_pr\",\n \"Approve and merge a child task's pull request. Pass projectId to target a specific project; otherwise the configured default project is used. Only succeeds if all CI/CD checks are passing. The child task must be in ReviewPR status with a PR.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n childTaskId: z.string().describe(\"The child task ID whose PR should be approved and merged\"),\n },\n async (params) => {\n const result = await conn.approveAndMergePR(params.childTaskId, params.projectId);\n return {\n content: [\n {\n type: \"text\",\n text: `PR #${result.prNumber} approved and merged for task ${result.childTaskId}`,\n },\n ],\n };\n },\n );\n\n server.tool(\n \"request_changes\",\n \"Post feedback and send task back to InProgress for more work. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n feedback: z.string().describe(\"Feedback message describing requested changes\"),\n risk: z\n .enum(RISK_ENUM)\n .optional()\n .describe(\"Optional risk level to record; defaults to a raise-only 'medium' on changes.\"),\n },\n async (params) => {\n await conn.requestChanges(params.taskId, params.feedback, params.projectId, params.risk);\n return { content: [{ type: \"text\", text: \"Changes requested, task moved to InProgress\" }] };\n },\n );\n}\n\nfunction formatReviewerList(reviewers: Array<{ userId: string; name: string | null }>): string {\n if (reviewers.length === 0) return \"none\";\n return reviewers.map((r) => `${r.name ?? \"unknown\"} (${r.userId})`).join(\", \");\n}\n\nfunction registerReviewerTools(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"add_reviewer\",\n \"Add a project member as a reviewer on a task. Pass projectId to target a specific project; otherwise the configured default project is used. Idempotent — adding an existing reviewer is a no-op.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n userId: z\n .string()\n .describe(\"User ID of the reviewer (use list_project_members to resolve a name or email)\"),\n },\n async (params) => {\n const result = await conn.addReviewer(params);\n return {\n content: [\n {\n type: \"text\",\n text: `Reviewer added to task ${result.taskId}. Reviewers: ${formatReviewerList(result.reviewers)}`,\n },\n ],\n };\n },\n );\n\n server.tool(\n \"remove_reviewer\",\n \"Remove a reviewer from a task. Pass projectId to target a specific project; otherwise the configured default project is used. Idempotent — removing a non-reviewer is a no-op.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n userId: z.string().describe(\"User ID of the reviewer to remove\"),\n },\n async (params) => {\n const result = await conn.removeReviewer(params);\n return {\n content: [\n {\n type: \"text\",\n text: `Reviewer removed from task ${result.taskId}. Reviewers: ${formatReviewerList(result.reviewers)}`,\n },\n ],\n };\n },\n );\n}\n\nexport function registerTaskTools(server: McpServer, conn: ConveyorConnection): void {\n registerListTasks(server, conn);\n registerGetTask(server, conn);\n registerGetCardBySlug(server, conn);\n registerCreateTask(server, conn);\n registerUpdateTask(server, conn);\n registerMoveCard(server, conn);\n registerChatTools(server, conn);\n registerGetTaskCli(server, conn);\n registerGetTaskSessions(server, conn);\n registerSearchTasks(server, conn);\n registerListTags(server, conn);\n registerReviewTools(server, conn);\n registerReviewerTools(server, conn);\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\n\nfunction textResult(result: unknown): { content: Array<{ type: \"text\"; text: string }> } {\n return { content: [{ type: \"text\", text: JSON.stringify(result, null, 2) }] };\n}\n\nfunction registerTaskLifecycleTools(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"stop_task\",\n \"Compatibility alias for the legacy stop path. stop_task now performs the same durable sleep behavior as sleep_task, preserving task Claudespace state while stopping compute. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n },\n async (params) => textResult(await conn.sleepTask(params.taskId, params.projectId)),\n );\n\n server.tool(\n \"sleep_task\",\n \"Sleep a task Claudespace, stopping compute while preserving durable state. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n },\n async (params) => textResult(await conn.sleepTask(params.taskId, params.projectId)),\n );\n\n server.tool(\n \"resume_task\",\n \"Resume a sleeping task Claudespace. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n },\n async (params) => textResult(await conn.resumeTask(params.taskId, params.projectId)),\n );\n\n server.tool(\n \"delete_task_environment\",\n \"Delete a task environment, including durable Claudespace state. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n },\n async (params) => textResult(await conn.deleteTaskEnvironment(params.taskId, params.projectId)),\n );\n}\n\nexport function registerBuildTools(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"start_task\",\n \"Start a cloud build (codespace) for a task. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n },\n async (params) => {\n const result = await conn.startBuild(params.taskId, params.projectId);\n return textResult(result);\n },\n );\n\n registerTaskLifecycleTools(server, conn);\n\n server.tool(\n \"create_release\",\n \"Create a release for the project — the same flow as the Release button in the web UI. Pass projectId to target a specific project; otherwise the configured default project is used. Creates a release task with a release/YYYY.MM.N branch and a PR from the dev branch to the default branch. Omit taskIds to release ALL cards currently in Review (Dev); pass a subset to cherry-pick — a cloud build agent then cherry-picks those changes and resolves conflicts. Fails if a release is already in progress or no cards are in Review (Dev).\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskIds: z\n .array(z.string())\n .optional()\n .describe(\n \"Task IDs in Review (Dev) to cherry-pick into the release. Omit to release all of them.\",\n ),\n },\n async (params) => {\n const result = await conn.createRelease(params.taskIds, params.projectId);\n return textResult(result);\n },\n );\n\n server.tool(\n \"get_build_status\",\n \"Check codespace and agent status for a task. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n },\n async (params) => {\n const status = await conn.getBuildStatus(params.taskId, params.projectId);\n return textResult(status);\n },\n );\n}\n","import { readFile, stat } from \"node:fs/promises\";\nimport { basename, extname } from \"node:path\";\nimport { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\n\n// Mirrors MAX_FILE_SIZE_BYTES in @project/shared service-map.ts (conveyor-mcp\n// has no workspace dependencies — the server enforces the real limit).\nconst MAX_FILE_SIZE_BYTES = 25 * 1024 * 1024;\n\nconst MIME_BY_EXT: Record<string, string> = {\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".svg\": \"image/svg+xml\",\n \".txt\": \"text/plain\",\n \".log\": \"text/plain\",\n \".md\": \"text/markdown\",\n \".csv\": \"text/csv\",\n \".html\": \"text/html\",\n \".css\": \"text/css\",\n \".js\": \"text/javascript\",\n \".ts\": \"text/plain\",\n \".json\": \"application/json\",\n \".yaml\": \"application/yaml\",\n \".yml\": \"application/yaml\",\n \".pdf\": \"application/pdf\",\n \".zip\": \"application/zip\",\n \".gz\": \"application/gzip\",\n \".mp4\": \"video/mp4\",\n \".webm\": \"video/webm\",\n \".mp3\": \"audio/mpeg\",\n \".wav\": \"audio/wav\",\n};\n\nexport function inferMimeType(filePath: string, override?: string): string {\n if (override) return override;\n return MIME_BY_EXT[extname(filePath).toLowerCase()] ?? \"application/octet-stream\";\n}\n\nfunction registerListTaskFiles(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"list_task_files\",\n \"List all files attached to a task with metadata (no contents — fast and small). Pass projectId to target a specific project; otherwise the configured default project is used. Use before fetching a specific file to see what is available and how large each is. For file contents use get_attachment.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n },\n async (params) => {\n const files = await conn.listTaskFiles(params.taskId, params.projectId);\n return { content: [{ type: \"text\", text: JSON.stringify(files, null, 2) }] };\n },\n );\n}\n\nexport interface AttachmentResult {\n fileName?: string;\n mimeType?: string;\n fileSize?: number;\n content?: string;\n contentEncoding?: string;\n contentByteOffset?: number;\n contentTotalBytes?: number;\n contentTruncated?: boolean;\n downloadUrl?: string;\n}\n\nexport type AttachmentContentBlock =\n | { type: \"text\"; text: string }\n | { type: \"image\"; data: string; mimeType: string };\n\nfunction buildTextContent(file: AttachmentResult, content: string): AttachmentContentBlock[] {\n const start = file.contentByteOffset ?? 0;\n const shown = Buffer.byteLength(content, \"utf-8\");\n const total = file.contentTotalBytes ?? shown;\n const more = file.contentTruncated\n ? ` — showing bytes ${start}–${start + shown} of ${total}; pass offset=${start + shown} for the next page, or fetch the full file at downloadUrl`\n : \"\";\n const header = `${file.fileName ?? \"file\"} (${file.mimeType ?? \"?\"}, ${total} bytes)${more}\\n${file.downloadUrl ? `downloadUrl: ${file.downloadUrl}\\n` : \"\"}---\\n`;\n return [{ type: \"text\", text: header + content }];\n}\n\nfunction buildImageContent(\n file: AttachmentResult,\n content: string,\n mimeType: string,\n): AttachmentContentBlock[] {\n const header = `${file.fileName ?? \"file\"} (${mimeType}, ${file.fileSize ?? \"?\"} bytes)${file.downloadUrl ? `\\ndownloadUrl: ${file.downloadUrl}` : \"\"}`;\n return [\n { type: \"text\", text: header },\n { type: \"image\", data: content, mimeType },\n ];\n}\n\n/**\n * Convert an attachment DTO into MCP content blocks.\n *\n * - utf-8 text → metadata/paging header + raw text (not JSON.stringify'd —\n * that double-escapes it).\n * - base64 images → metadata header + a proper MCP image block so the model\n * actually sees the image. Dumping base64 into a text block both blows the\n * client's token limit and is unviewable.\n * - anything else → metadata JSON with `content` stripped, so inlined bytes\n * can never leak into a text block.\n */\nexport function buildAttachmentContent(file: AttachmentResult): AttachmentContentBlock[] {\n if (typeof file.content === \"string\" && file.contentEncoding === \"utf-8\") {\n return buildTextContent(file, file.content);\n }\n if (\n typeof file.content === \"string\" &&\n file.contentEncoding === \"base64\" &&\n file.mimeType?.startsWith(\"image/\")\n ) {\n return buildImageContent(file, file.content, file.mimeType);\n }\n const { content: _content, ...metadata } = file;\n return [{ type: \"text\", text: JSON.stringify(metadata, null, 2) }];\n}\n\nfunction registerGetAttachment(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"get_attachment\",\n \"Fetch one task file's content plus metadata by file ID (accepts task id or slug). Pass projectId to target a specific project; otherwise the configured default project is used. Images are returned as viewable image blocks. Large text files (logs, JSON) are returned in pages — use `offset`/`maxBytes` to read more, or fetch `downloadUrl` for the whole file. Call list_task_files first to discover IDs and sizes.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n fileId: z.string().describe(\"The file ID to fetch\"),\n offset: z\n .number()\n .int()\n .nonnegative()\n .optional()\n .describe(\"Byte offset into text content (paging). Default 0.\"),\n maxBytes: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\"Max bytes of text content to return from offset.\"),\n },\n async (params) => {\n const file = (await conn.getAttachment(params.taskId, params.fileId, {\n offset: params.offset,\n maxBytes: params.maxBytes,\n projectId: params.projectId,\n })) as AttachmentResult;\n return { content: buildAttachmentContent(file) };\n },\n );\n}\n\nfunction registerUploadAttachment(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"upload_attachment\",\n \"Upload a local file as a task attachment (any file type, up to 25MB). Pass projectId to target a specific project; otherwise the configured default project is used. The file appears under the task's Files. Pass `comment` to also post it to the task chat in the same step.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n path: z.string().describe(\"Absolute path to the local file to upload\"),\n comment: z\n .string()\n .optional()\n .describe(\"When set, also posts the attachment to the task chat with this text\"),\n mimeType: z\n .string()\n .optional()\n .describe(\"Override the mime type inferred from the file extension\"),\n },\n async (params) => {\n const info = await stat(params.path).catch(() => null);\n if (!info?.isFile()) {\n return { content: [{ type: \"text\" as const, text: `File not found: ${params.path}` }] };\n }\n if (info.size > MAX_FILE_SIZE_BYTES) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `File is ${info.size} bytes — exceeds the ${MAX_FILE_SIZE_BYTES} byte (25MB) upload limit.`,\n },\n ],\n };\n }\n\n const fileName = basename(params.path);\n const mimeType = inferMimeType(params.path, params.mimeType);\n const { fileId, uploadUrl } = await conn.requestFileUpload(params.taskId, {\n fileName,\n mimeType,\n fileSize: info.size,\n projectId: params.projectId,\n });\n\n // PUT raw bytes to the capability upload URL (the API byte-proxy streams\n // them to GCS). Content-Type carries the mime so the stored object is set.\n const body = await readFile(params.path);\n const res = await fetch(uploadUrl, {\n method: \"PUT\",\n headers: { \"Content-Type\": mimeType },\n body,\n });\n if (!res.ok) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Upload to storage failed: HTTP ${res.status} ${await res.text().catch(() => \"\")}`,\n },\n ],\n };\n }\n\n const result = await conn.confirmFileUpload(\n params.taskId,\n fileId,\n params.comment,\n params.projectId,\n );\n const lines = [\n `Uploaded ${result.fileName} (${info.size} bytes, ${mimeType}). File ID: ${result.fileId}`,\n ];\n if (result.downloadUrl) lines.push(`downloadUrl: ${result.downloadUrl}`);\n if (result.messageId) lines.push(\"Posted to the task chat.\");\n return { content: [{ type: \"text\" as const, text: lines.join(\"\\n\") }] };\n },\n );\n}\n\nexport function registerAttachmentTools(server: McpServer, conn: ConveyorConnection): void {\n registerListTaskFiles(server, conn);\n registerGetAttachment(server, conn);\n registerUploadAttachment(server, conn);\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\n\nexport function registerPullRequestTools(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"create_pull_request\",\n \"Open a GitHub pull request for a task's existing branch (the branch must already be pushed to origin). Pass projectId to target a specific project; otherwise the configured default project is used. Moves the task to ReviewPR. Returns the PR number and URL.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID whose branch should be opened as a PR\"),\n title: z.string().describe(\"Pull request title\"),\n body: z.string().describe(\"Pull request body (markdown)\"),\n head: z\n .string()\n .optional()\n .describe(\"Source branch for the PR (defaults to the task's branch)\"),\n base: z\n .string()\n .optional()\n .describe(\"Target branch for the PR (defaults to the repo default)\"),\n },\n async (params) => {\n const result = await conn.createPullRequest(params);\n return {\n content: [{ type: \"text\", text: `PR #${result.prNumber} opened: ${result.prUrl}` }],\n };\n },\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\n\nconst STATUS_ENUM = [\n \"Planning\",\n \"Open\",\n \"InProgress\",\n \"ReviewPR\",\n \"ReviewDev\",\n \"ReviewLive\",\n \"Complete\",\n \"Cancelled\",\n] as const;\n\nconst SP_DESCRIPTION = \"Story point value (1=Common, 2=Magic, 3=Rare, 5=Unique)\";\nconst FOLLOW_PARENT_STATUS_DESCRIPTION =\n \"When true, this subtask mirrors the parent task's status automatically — for children that ship on the parent's branch/PR and have no build or PR of their own. Manual status writes on a follower stick only until the parent's next transition.\";\n\nfunction registerCreateSubtask(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"create_subtask\",\n \"Create a subtask under a parent task. Pass projectId to target a specific project; otherwise the configured default project is used. Subtasks break a larger task into independently buildable pieces. For children that instead ship on the parent's own branch/PR (e.g. per-theme tracking cards for one bundled PR), set followParentStatus so their status rides the parent's automatically.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n parentTaskId: z.string().describe(\"The parent task ID\"),\n title: z.string().describe(\"Subtask title\"),\n description: z.string().optional().describe(\"Subtask description\"),\n plan: z.string().optional().describe(\"Subtask implementation plan (markdown)\"),\n ordinal: z.number().optional().describe(\"Ordering position among siblings\"),\n storyPointValue: z.number().optional().describe(SP_DESCRIPTION),\n followParentStatus: z.boolean().optional().describe(FOLLOW_PARENT_STATUS_DESCRIPTION),\n dependsOn: z\n .array(z.string())\n .optional()\n .describe(\n \"Sibling subtask ids or slugs this subtask blocks on (it won't start until they merge to dev). Set explicit dependency metadata here instead of describing order in the plan text. Omit / leave empty for independent children so they run in parallel.\",\n ),\n },\n async (params) => {\n const subtask = await conn.createSubtask(params);\n return {\n content: [{ type: \"text\", text: `Subtask created: ${subtask.id} (slug: ${subtask.slug})` }],\n };\n },\n );\n}\n\nfunction registerUpdateSubtask(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"update_subtask\",\n \"Update a subtask's fields: title, description, plan, status, ordering, or story points. Pass projectId to target a specific project; otherwise the configured default project is used. Moving a subtask beyond Planning auto-fills missing story points and agent assignment — don't spend turns on them.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n subtaskId: z.string().describe(\"The subtask ID\"),\n title: z.string().optional().describe(\"New title\"),\n description: z.string().optional().describe(\"New description\"),\n plan: z.string().optional().describe(\"New plan (markdown)\"),\n status: z.enum(STATUS_ENUM).optional().describe(\"New status\"),\n ordinal: z.number().optional().describe(\"New ordering position among siblings\"),\n storyPointValue: z.number().optional().describe(SP_DESCRIPTION),\n followParentStatus: z.boolean().optional().describe(FOLLOW_PARENT_STATUS_DESCRIPTION),\n },\n async (params) => {\n const result = await conn.updateSubtask(params);\n return {\n content: [\n { type: \"text\", text: `Subtask ${result.id} updated (status: ${result.status})` },\n ],\n };\n },\n );\n}\n\nfunction registerListSubtasks(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"list_subtasks\",\n \"List all subtasks of a parent task with their status and ordering. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The parent task ID\"),\n },\n async (params) => {\n const subtasks = await conn.listSubtasks(params.taskId, params.projectId);\n return { content: [{ type: \"text\", text: JSON.stringify(subtasks, null, 2) }] };\n },\n );\n}\n\nfunction registerDeleteSubtask(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"delete_subtask\",\n \"Delete a subtask by ID. Pass projectId to target a specific project; otherwise the configured default project is used. This is permanent — use update_subtask to set status to Cancelled if you only want to close it.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n subtaskId: z.string().describe(\"The subtask ID to delete\"),\n },\n async (params) => {\n const result = await conn.deleteSubtask(params.subtaskId, params.projectId);\n return {\n content: [\n { type: \"text\", text: result.deleted ? \"Subtask deleted\" : \"Subtask not deleted\" },\n ],\n };\n },\n );\n}\n\nexport function registerSubtaskTools(server: McpServer, conn: ConveyorConnection): void {\n registerCreateSubtask(server, conn);\n registerUpdateSubtask(server, conn);\n registerListSubtasks(server, conn);\n registerDeleteSubtask(server, conn);\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\n\nfunction registerGetDependencies(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"get_dependencies\",\n \"Get a task's dependencies and their met/unmet status (met = merged to dev). Pass projectId to target a specific project; otherwise the configured default project is used. Use to confirm blockers merged, or see why a task cannot start. For task state use get_task.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID\"),\n },\n async (params) => {\n const deps = await conn.getDependencies(params.taskId, params.projectId);\n return { content: [{ type: \"text\", text: JSON.stringify(deps, null, 2) }] };\n },\n );\n}\n\nfunction registerAddDependency(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"add_dependency\",\n \"Add a blocking dependency — this task cannot start until the named task is merged to dev. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID that will be blocked\"),\n dependsOnSlugOrId: z.string().describe(\"Slug or ID of the task this one depends on\"),\n },\n async (params) => {\n await conn.addDependency(params);\n return { content: [{ type: \"text\", text: \"Dependency added\" }] };\n },\n );\n}\n\nfunction registerRemoveDependency(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"remove_dependency\",\n \"Remove a previously added dependency from a task. Pass projectId to target a specific project; otherwise the configured default project is used. The task is no longer blocked by the named task. Returns: confirmation string.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID to unblock\"),\n dependsOnSlugOrId: z.string().describe(\"Slug or ID of the dependency to remove\"),\n },\n async (params) => {\n await conn.removeDependency(params);\n return { content: [{ type: \"text\", text: \"Dependency removed\" }] };\n },\n );\n}\n\nexport function registerDependencyTools(server: McpServer, conn: ConveyorConnection): void {\n registerGetDependencies(server, conn);\n registerAddDependency(server, conn);\n registerRemoveDependency(server, conn);\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\n\nexport function registerSuggestionTools(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"create_suggestion\",\n \"Suggest a feature, improvement, rule, or idea for the project. Pass projectId to target a specific project; otherwise the configured default project is used. Duplicates are deduped and your upvote is recorded.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n title: z.string().describe(\"Suggestion title\"),\n description: z.string().optional().describe(\"Suggestion details (markdown)\"),\n tagNames: z\n .array(z.string())\n .optional()\n .describe('Tag names to categorize the suggestion (e.g., [\"agent-runner\"])'),\n },\n async (params) => {\n const result = await conn.createSuggestion(params);\n const text = result.merged\n ? `Suggestion merged into existing suggestion ${result.mergedIntoId} (upvote recorded)`\n : `Suggestion created: ${result.id}`;\n return { content: [{ type: \"text\", text }] };\n },\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\n\ntype ManualTestGroup = Awaited<ReturnType<ConveyorConnection[\"queryManualTests\"]>>[number];\n\n/** Compact grouped rendering for cross-task manual-test queries: one header per\n * task, one line per test with a status glyph, and the failing reason indented\n * under each rejected test. */\nfunction renderManualTestGroups(groups: ManualTestGroup[]): string {\n const lines: string[] = [];\n for (const g of groups) {\n lines.push(`## ${g.title} [${g.status}] (${g.slug})`);\n for (const t of g.tests) {\n const mark = t.status === \"approved\" ? \"✓\" : t.status === \"rejected\" ? \"✗\" : \"○\";\n lines.push(` ${mark} ${t.title} — ${t.status}`);\n if (t.status === \"rejected\") {\n for (const f of t.failures) {\n lines.push(` ⚠ ${f.userName ?? \"Someone\"}: ${f.reason ?? \"(no message)\"}`);\n }\n }\n }\n lines.push(\"\");\n }\n return lines.join(\"\\n\").trimEnd();\n}\n\nfunction registerListManualTests(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"list_manual_tests\",\n \"List the manual test checklist items for a task. Pass projectId to target a specific project; otherwise the configured default project is used. Use to see what manual verification steps have already been recorded.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug (the value in a card URL, /cards/<slug>)\"),\n },\n async (params) => {\n const items = await conn.listManualTests(params.taskId, params.projectId);\n if (items.length === 0) {\n return { content: [{ type: \"text\", text: \"No manual tests recorded for this task.\" }] };\n }\n const lines = items.flatMap((item, i) => {\n const checked = item.checked ? \"[x]\" : \"[ ]\";\n const row = [`${i + 1}. ${checked} ${item.title}`];\n for (const f of item.failures ?? []) {\n const who = f.userName ?? \"Someone\";\n const reason = f.reason ?? \"(no message)\";\n row.push(` ⚠ Failed (${who}): ${reason}`);\n }\n return row;\n });\n return { content: [{ type: \"text\", text: lines.join(\"\\n\") }] };\n },\n );\n}\n\nfunction registerSetManualTests(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"set_manual_tests\",\n \"Add manual test steps to a task's checklist. Pass projectId to target a specific project; otherwise the configured default project is used. Existing items with the same title are automatically skipped (deduplication). Use to record specific manual verification steps that reviewers should follow when testing the task's PR.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n items: z\n .array(z.object({ title: z.string().min(1).describe(\"A concise, actionable test step\") }))\n .min(1)\n .describe(\"List of manual test steps to add\"),\n },\n async (params) => {\n const result = await conn.setManualTests(params.taskId, params.items, params.projectId);\n const parts = [`Created ${result.created} manual test item(s).`];\n if (result.skipped > 0) parts.push(`Skipped ${result.skipped} duplicate(s).`);\n return { content: [{ type: \"text\", text: parts.join(\" \") }] };\n },\n );\n}\n\nfunction registerEditManualTest(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"edit_manual_test\",\n \"Rename an existing manual test step on a task. Pass projectId to target a specific project; otherwise the configured default project is used. Identify the test by its current title (case-insensitive) and pass the new title to replace it.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n title: z.string().min(1).describe(\"The current title of the manual test to edit\"),\n newTitle: z.string().min(1).describe(\"The new title for the manual test\"),\n },\n async (params) => {\n await conn.editManualTest(params.taskId, params.title, params.newTitle, params.projectId);\n return { content: [{ type: \"text\", text: `Updated manual test to \"${params.newTitle}\".` }] };\n },\n );\n}\n\nfunction registerRemoveManualTest(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"remove_manual_test\",\n \"Remove an existing manual test step from a task's checklist. Pass projectId to target a specific project; otherwise the configured default project is used. Identify the test by its title (case-insensitive).\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n title: z.string().min(1).describe(\"The title of the manual test to remove\"),\n },\n async (params) => {\n await conn.removeManualTest(params.taskId, params.title, params.projectId);\n return { content: [{ type: \"text\", text: `Removed manual test \"${params.title}\".` }] };\n },\n );\n}\n\nfunction registerApproveManualTest(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"approve_manual_test\",\n \"Sign off on (approve) a manual test step on a task on behalf of your authenticated user. Pass projectId to target a specific project; otherwise the configured default project is used. Identify the test by its title (case-insensitive). Use after you have verified the step passes.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n title: z.string().min(1).describe(\"The title of the manual test to approve\"),\n },\n async (params) => {\n await conn.approveManualTest(params.taskId, params.title, params.projectId);\n return { content: [{ type: \"text\", text: `Approved manual test \"${params.title}\".` }] };\n },\n );\n}\n\nfunction registerRejectManualTest(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"reject_manual_test\",\n \"Flag an issue with (reject) a manual test step on a task on behalf of your authenticated user, recording the reason. Pass projectId to target a specific project; otherwise the configured default project is used. Identify the test by its title (case-insensitive). Use when the step fails verification.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n taskId: z.string().describe(\"The task ID or slug\"),\n title: z.string().min(1).describe(\"The title of the manual test to reject\"),\n reason: z\n .string()\n .min(1)\n .max(2000)\n .describe(\"Why the test failed — what went wrong, shown to the team\"),\n },\n async (params) => {\n await conn.rejectManualTest(params.taskId, params.title, params.reason, params.projectId);\n return {\n content: [\n {\n type: \"text\",\n text: `Flagged an issue with manual test \"${params.title}\": ${params.reason}`,\n },\n ],\n };\n },\n );\n}\n\nfunction registerQueryManualTests(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"query_manual_tests\",\n \"Query manual tests across many tasks in a project, grouped by task. Filter by card status (e.g. ReviewDev, ReviewLive, Complete) and/or test status (open | approved | rejected). Use to answer questions like 'show all OPEN manual tests in ReviewDev' or 'show all REJECTED manual tests in ReviewDev/ReviewLive with the failing reason'. With no filters it defaults to the needs-attention view: open+rejected tests on ReviewDev/ReviewLive cards. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n cardStatuses: z\n .array(z.string())\n .optional()\n .describe('Filter tasks by card/column status, e.g. [\"ReviewDev\", \"ReviewLive\"]'),\n testStatuses: z\n .array(z.enum([\"open\", \"approved\", \"rejected\"]))\n .optional()\n .describe(\"Filter tests by status: open | approved | rejected\"),\n },\n async (params) => {\n const groups = await conn.queryManualTests({\n projectId: params.projectId,\n cardStatuses: params.cardStatuses,\n testStatuses: params.testStatuses,\n });\n if (groups.length === 0) {\n return { content: [{ type: \"text\", text: \"No manual tests match those filters.\" }] };\n }\n return { content: [{ type: \"text\", text: renderManualTestGroups(groups) }] };\n },\n );\n}\n\nexport function registerChecklistTools(server: McpServer, conn: ConveyorConnection): void {\n registerListManualTests(server, conn);\n registerQueryManualTests(server, conn);\n registerSetManualTests(server, conn);\n registerEditManualTest(server, conn);\n registerRemoveManualTest(server, conn);\n registerApproveManualTest(server, conn);\n registerRejectManualTest(server, conn);\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\nimport {\n startWorkspaceSshTunnel,\n type WorkspaceSshTunnelHandle,\n type WorkspaceSshTunnelOptions,\n} from \"../workspace-ssh-tunnel.js\";\n\ninterface WorkspaceToolDeps {\n startTunnel?: (options: WorkspaceSshTunnelOptions) => Promise<WorkspaceSshTunnelHandle>;\n}\n\nconst activeTunnels = new Map<string, WorkspaceSshTunnelHandle>();\n\nfunction createTunnelId(taskId: string, port: number): string {\n return `${taskId}:${port}:${Date.now().toString(36)}:${Math.random().toString(36).slice(2, 8)}`;\n}\n\nfunction localUrlFor(port: number, host: string, localPort: number): string | undefined {\n if (port === 2222) return undefined;\n return `http://${host}:${localPort}`;\n}\n\nfunction registerAttachInfoTool(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"workspace_attach_info\",\n \"Return SSH/SFTP attach metadata for a running task Claudespace, plus hosted preview URLs and configured preview ports. Optionally installs an OpenSSH public key for this attach session.\",\n {\n taskId: z.string().describe(\"The task ID\"),\n sshPublicKey: z\n .string()\n .optional()\n .describe(\"Optional OpenSSH public key to install into the workspace\"),\n },\n async ({ taskId, sshPublicKey }) => {\n const info = await conn.getWorkspaceAttachInfo(taskId, sshPublicKey);\n return { content: [{ type: \"text\", text: JSON.stringify(info, null, 2) }] };\n },\n );\n}\n\nfunction registerPreviewUrlsTool(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"workspace_preview_urls\",\n \"Return the hosted preview URLs and preview ports for a running task Claudespace. This mirrors the web UI preview link metadata.\",\n {\n taskId: z.string().describe(\"The task ID\"),\n },\n async ({ taskId }) => {\n const info = await conn.getWorkspaceAttachInfo(taskId);\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n {\n taskId: info.taskId,\n sessionId: info.sessionId,\n previewPorts: info.previewPorts,\n previewUrls: info.previewUrls,\n },\n null,\n 2,\n ),\n },\n ],\n };\n },\n );\n}\n\nfunction registerStartTunnelTool(\n server: McpServer,\n conn: ConveyorConnection,\n startTunnel: (options: WorkspaceSshTunnelOptions) => Promise<WorkspaceSshTunnelHandle>,\n): void {\n server.tool(\n \"workspace_start_tunnel\",\n \"Start a local loopback tunnel through the MCP server to a running task Claudespace port. Use port 2222 for SSH/SFTP, or one of previewPorts for app access.\",\n {\n taskId: z.string().describe(\"The task ID\"),\n port: z.number().optional().describe(\"Remote Claudespace port. Defaults to SSH port 2222.\"),\n preferredLocalPort: z\n .number()\n .optional()\n .describe(\"Preferred local loopback port. If omitted, the OS chooses one.\"),\n sshPublicKey: z\n .string()\n .optional()\n .describe(\"Optional OpenSSH public key to install before opening the tunnel\"),\n },\n async ({ taskId, port, preferredLocalPort, sshPublicKey }) => {\n const info = await conn.getWorkspaceAttachInfo(taskId, sshPublicKey);\n const remotePort = port ?? info.ssh?.remotePort ?? 2222;\n const handle = await startTunnel({\n remotePort,\n preferredLocalPort,\n // Re-mint per connection so the tunnel outlives the attach-token TTL.\n // The key (if any) is already installed by the call above; the refetch\n // only needs a fresh token, so it omits sshPublicKey.\n resolveTarget: async () => {\n const fresh = await conn.getWorkspaceAttachInfo(taskId);\n return { tunnelUrl: fresh.tunnelUrl, attachToken: fresh.attachToken };\n },\n });\n const tunnelId = createTunnelId(taskId, remotePort);\n activeTunnels.set(tunnelId, handle);\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n {\n tunnelId,\n taskId,\n remotePort,\n localHost: handle.host,\n localPort: handle.port,\n localUrl: localUrlFor(remotePort, handle.host, handle.port),\n // `-o ServerAliveInterval=30` drives client-side keepalives so an\n // idle session keeps the tunnel warm (the tunnel layer pings too,\n // but the client must keep its own TCP path alive across every hop).\n sshCommand:\n remotePort === 2222\n ? `ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -p ${handle.port} ${info.ssh?.username ?? \"conveyor\"}@${handle.host}`\n : undefined,\n sftpCommand:\n remotePort === 2222\n ? `sftp -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -P ${handle.port} ${info.ssh?.username ?? \"conveyor\"}@${handle.host}`\n : undefined,\n previewPorts: info.previewPorts,\n previewUrls: info.previewUrls,\n expiresAt: info.expiresAt,\n },\n null,\n 2,\n ),\n },\n ],\n };\n },\n );\n}\n\nfunction registerStopTunnelTool(server: McpServer): void {\n server.tool(\n \"workspace_stop_tunnel\",\n \"Stop a local workspace tunnel previously opened by workspace_start_tunnel.\",\n {\n tunnelId: z.string().describe(\"Tunnel id returned by workspace_start_tunnel\"),\n },\n async ({ tunnelId }) => {\n const tunnel = activeTunnels.get(tunnelId);\n if (!tunnel) throw new Error(\"Workspace tunnel not found\");\n await tunnel.close();\n activeTunnels.delete(tunnelId);\n return { content: [{ type: \"text\", text: \"Workspace tunnel stopped\" }] };\n },\n );\n}\n\nexport function registerWorkspaceTools(\n server: McpServer,\n conn: ConveyorConnection,\n deps: WorkspaceToolDeps = {},\n): void {\n registerAttachInfoTool(server, conn);\n registerPreviewUrlsTool(server, conn);\n registerStartTunnelTool(server, conn, deps.startTunnel ?? startWorkspaceSshTunnel);\n registerStopTunnelTool(server);\n}\n","import net from \"node:net\";\nimport { once } from \"node:events\";\nimport { WebSocket } from \"ws\";\n\n// Mirrors WORKSPACE_TUNNEL_HEARTBEAT_MS in @project/shared constants/workspace-tunnel.ts\n// (conveyor-mcp has no workspace dependencies — the two tunnel ends share this\n// value by convention). Cloudflare reaps idle proxied WebSockets, so both ends\n// ping on this interval to keep the edge connection warm.\nconst WORKSPACE_TUNNEL_HEARTBEAT_MS = 30_000;\n\nexport interface WorkspaceTunnelTarget {\n tunnelUrl: string;\n attachToken: string;\n}\n\nexport interface WorkspaceSshTunnelOptions {\n // Minted fresh for every local connection so long-lived clients (VS Code\n // Remote-SSH / SSHFS open many short connections over one session) keep\n // working after the short-lived attach token expires — no refresh plumbing,\n // just re-fetch on connect.\n resolveTarget: () => Promise<WorkspaceTunnelTarget>;\n remotePort: number;\n preferredLocalPort?: number;\n host?: string;\n}\n\nexport interface WorkspaceSshTunnelHandle {\n host: string;\n port: number;\n close: () => Promise<void>;\n}\n\nfunction withPort(url: string, port: number): string {\n const parsed = new URL(url);\n parsed.searchParams.set(\"port\", String(port));\n return parsed.toString();\n}\n\nfunction toBuffer(data: WebSocket.RawData): Buffer {\n if (Buffer.isBuffer(data)) return data;\n if (data instanceof ArrayBuffer) return Buffer.from(data);\n return Buffer.concat(data);\n}\n\n// Ping from this end too: a long-lived single connection (interactive `ssh`,\n// `ssh -L` forward) carries no traffic while idle, and Cloudflare reaps idle\n// proxied WebSockets. The heartbeat keeps the upstream warm so the tunnel\n// lives as long as the workspace, not just until the next idle reap.\nfunction startHeartbeat(ws: WebSocket): () => void {\n const timer = setInterval(() => {\n if (ws.readyState === WebSocket.OPEN) ws.ping();\n }, WORKSPACE_TUNNEL_HEARTBEAT_MS);\n timer.unref?.();\n return () => clearInterval(timer);\n}\n\n// Bridge one accepted local connection (ssh/sftp) to a freshly-minted upstream\n// WebSocket. Each local connection re-mints via `resolveTarget`, so long-lived\n// clients keep working past the attach-token TTL.\nfunction bridgeClient(client: net.Socket, options: WorkspaceSshTunnelOptions): void {\n let ws: WebSocket | null = null;\n let ready = false;\n // Client (ssh) bytes can arrive before the async re-mint + WS open; hold\n // them until the upstream is ready so the handshake isn't dropped.\n const pending: Buffer[] = [];\n client.on(\"data\", (chunk) => {\n if (ready && ws && ws.readyState === WebSocket.OPEN) ws.send(chunk);\n else pending.push(chunk);\n });\n client.on(\"close\", () => ws?.close());\n client.on(\"error\", () => ws?.close());\n\n options\n .resolveTarget()\n .then(({ tunnelUrl, attachToken }) => {\n // Token rides in a header, not the query string, so it isn't captured\n // by edge/proxy access logs. (Node `ws` can set request headers; the\n // browser WebSocket API can't — but this client is always Node.)\n const socket = new WebSocket(withPort(tunnelUrl, options.remotePort), {\n headers: { \"x-workspace-attach-token\": attachToken },\n });\n ws = socket;\n const stopHeartbeat = startHeartbeat(socket);\n socket.on(\"message\", (data) => {\n const chunk = toBuffer(data);\n if (!ready) {\n const text = chunk.toString(\"utf8\");\n if (text === JSON.stringify({ ok: true })) {\n ready = true;\n for (const buffered of pending.splice(0)) socket.send(buffered);\n return;\n }\n client.destroy(new Error(`Workspace tunnel rejected connection: ${text}`));\n socket.close();\n return;\n }\n client.write(chunk);\n });\n socket.on(\"close\", () => {\n stopHeartbeat();\n client.destroy();\n });\n socket.on(\"error\", (err) => {\n stopHeartbeat();\n client.destroy(err);\n });\n })\n .catch((err) => {\n client.destroy(err instanceof Error ? err : new Error(String(err)));\n });\n}\n\nexport async function startWorkspaceSshTunnel(\n options: WorkspaceSshTunnelOptions,\n): Promise<WorkspaceSshTunnelHandle> {\n const host = options.host ?? \"127.0.0.1\";\n const server = net.createServer((client) => bridgeClient(client, options));\n\n // Race \"listening\" against \"error\": a busy preferredLocalPort emits \"error\"\n // with no listener, which would otherwise crash the MCP process.\n const ac = new AbortController();\n server.listen(options.preferredLocalPort ?? 0, host);\n try {\n await Promise.race([\n once(server, \"listening\", { signal: ac.signal }),\n once(server, \"error\", { signal: ac.signal }).then(([err]) => {\n throw err instanceof Error ? err : new Error(String(err));\n }),\n ]);\n } catch (err) {\n server.close();\n throw new Error(\n `Failed to bind workspace SSH tunnel: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err },\n );\n } finally {\n ac.abort();\n }\n const address = server.address();\n if (!address || typeof address === \"string\") {\n server.close();\n throw new Error(\"Failed to bind workspace SSH tunnel\");\n }\n\n return {\n host,\n port: address.port,\n close: () =>\n new Promise<void>((resolve, reject) => {\n server.close((err) => {\n if (err) reject(err);\n else resolve();\n });\n }),\n };\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection, GcpLogEntry } from \"../connection.js\";\n\nconst SEVERITY_ENUM = [\n \"DEBUG\",\n \"INFO\",\n \"NOTICE\",\n \"WARNING\",\n \"ERROR\",\n \"CRITICAL\",\n \"ALERT\",\n \"EMERGENCY\",\n] as const;\n\nconst MAX_LINE_CHARS = 400;\nconst DEFAULT_SINCE_MINUTES = 60;\n\nfunction truncateLine(text: string): string {\n const oneLine = text.replace(/\\s*\\n\\s*/g, \" ⏎ \");\n if (oneLine.length <= MAX_LINE_CHARS) return oneLine;\n const overflow = oneLine.length - MAX_LINE_CHARS;\n return `${oneLine.slice(0, MAX_LINE_CHARS)}…[+${overflow}c]`;\n}\n\nfunction entrySource(entry: GcpLogEntry): string {\n return (\n entry.resource.service_name ??\n entry.resource.pod_name ??\n entry.resource.database_id ??\n entry.resourceType ??\n \"-\"\n );\n}\n\nexport function formatLogEntryLine(entry: GcpLogEntry): string {\n const httpPrefix = entry.httpRequest?.status\n ? `http ${entry.httpRequest.status} ${entry.httpRequest.method ?? \"\"} ${entry.httpRequest.url ?? \"\"}`.trim() +\n \" — \"\n : \"\";\n return `${entry.timestamp} ${entry.severity.padEnd(7)} [${entrySource(entry)}] ${truncateLine(\n `${httpPrefix}${entry.message}`,\n )}`;\n}\n\nexport interface QueryGcpLogsToolParams {\n projectId?: string;\n env?: \"prod\" | \"dev\" | \"claudespace\";\n sinceMinutes?: number;\n startTime?: string;\n endTime?: string;\n severity?: (typeof SEVERITY_ENUM)[number];\n services?: string[];\n sqlInstances?: string[];\n allServices?: boolean;\n search?: string;\n filter?: string;\n limit?: number;\n pageToken?: string;\n}\n\n/** Exported for tests — the tool handler minus MCP plumbing. */\nexport async function runQueryGcpLogs(\n conn: ConveyorConnection,\n params: QueryGcpLogsToolParams,\n now: () => number = Date.now,\n): Promise<string> {\n const startTime =\n params.startTime ??\n new Date(now() - (params.sinceMinutes ?? DEFAULT_SINCE_MINUTES) * 60_000).toISOString();\n\n const result = await conn.queryGcpLogs({\n projectId: params.projectId,\n env: params.env,\n severity: params.severity,\n services: params.services,\n sqlInstances: params.sqlInstances,\n allServices: params.allServices,\n search: params.search,\n filter: params.filter,\n startTime,\n endTime: params.endTime,\n limit: params.limit,\n pageToken: params.pageToken,\n });\n\n if (result.error) return result.error;\n\n const header = [\n `env=${params.env ?? \"prod\"}`,\n `window=${startTime}→${params.endTime ?? \"now\"}`,\n ...(params.severity ? [`minSeverity=${params.severity}`] : []),\n `scope=${result.scopedServices ? `[${result.scopedServices.join(\", \")}]` : \"all\"}`,\n `entries=${result.entries.length}`,\n ].join(\" \");\n\n const lines = result.entries.map(formatLogEntryLine);\n const footer = result.nextPageToken\n ? [`-- more available: pass pageToken=\"${result.nextPageToken}\" to continue`]\n : [];\n\n if (lines.length === 0) {\n return [\n header,\n \"(no matching log entries — widen the window, lower minSeverity, or drop filters)\",\n ].join(\"\\n\");\n }\n return [header, ...lines, ...footer].join(\"\\n\");\n}\n\nexport function registerLogTools(server: McpServer, conn: ConveyorConnection): void {\n server.tool(\n \"query_gcp_logs\",\n \"Query Google Cloud Logging for a project's linked GCP environments — use this to investigate production or dev issues directly ('something broke on prod'). Envs: 'prod' and 'dev' are the project's Cloud Run apps + Cloud SQL databases (scoped by default to the resources linked in project settings); 'claudespace' is the project's GKE agent-pod namespace. Start broad (severity=ERROR, sinceMinutes=60), then narrow with services/search. Returns compact lines: '<time> <SEVERITY> [<source>] <message>'. When the response ends with a pageToken line, pass that token back as pageToken for the next page. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n {\n projectId: z.string().optional().describe(\"Target Conveyor project ID\"),\n env: z\n .enum([\"prod\", \"dev\", \"claudespace\"])\n .optional()\n .describe(\"GCP environment slot to query (default prod)\"),\n sinceMinutes: z\n .number()\n .int()\n .min(1)\n .max(10080)\n .optional()\n .describe(\n \"Relative time window ending now, in minutes (default 60). Ignored if startTime is set.\",\n ),\n startTime: z.string().optional().describe(\"ISO 8601 lower bound (overrides sinceMinutes)\"),\n endTime: z.string().optional().describe(\"ISO 8601 upper bound (default now)\"),\n severity: z\n .enum(SEVERITY_ENUM)\n .optional()\n .describe(\"Minimum severity, inclusive — ERROR returns ERROR and above\"),\n services: z\n .array(z.string())\n .optional()\n .describe(\n \"Restrict to these Cloud Run service names (prod/dev only). Defaults to all services linked in project settings.\",\n ),\n sqlInstances: z\n .array(z.string())\n .optional()\n .describe(\"Restrict to these Cloud SQL instance names (prod/dev only)\"),\n allServices: z\n .boolean()\n .optional()\n .describe(\n \"Set true to search ALL logs in the GCP project, ignoring the linked-resource scope\",\n ),\n search: z\n .string()\n .max(256)\n .optional()\n .describe(\"Free-text search across all log fields (exact substring, not regex)\"),\n filter: z\n .string()\n .max(1000)\n .optional()\n .describe(\"Advanced: raw Cloud Logging filter expression, ANDed with the scope\"),\n limit: z\n .number()\n .int()\n .min(1)\n .max(200)\n .optional()\n .describe(\"Max entries per page (default 50)\"),\n pageToken: z\n .string()\n .optional()\n .describe(\"Opaque token from a previous response to fetch the next page\"),\n },\n async (params) => {\n const text = await runQueryGcpLogs(conn, params);\n return { content: [{ type: \"text\", text }] };\n },\n );\n}\n","/* oxlint-disable import/max-dependencies -- registration aggregator imports every tool module by design */\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ConveyorConnection } from \"../connection.js\";\nimport { registerProjectTools } from \"./project.js\";\nimport { registerTaskTools } from \"./tasks.js\";\nimport { registerBuildTools } from \"./builds.js\";\nimport { registerAttachmentTools } from \"./attachments.js\";\nimport { registerPullRequestTools } from \"./pull-request.js\";\nimport { registerSubtaskTools } from \"./subtasks.js\";\nimport { registerDependencyTools } from \"./dependencies.js\";\nimport { registerSuggestionTools } from \"./suggestions.js\";\nimport { registerChecklistTools } from \"./checklists.js\";\nimport { registerWorkspaceTools } from \"./workspace.js\";\nimport { registerLogTools } from \"./logs.js\";\n\nexport function registerAllTools(server: McpServer, conn: ConveyorConnection): void {\n registerProjectTools(server, conn);\n registerTaskTools(server, conn);\n registerBuildTools(server, conn);\n registerAttachmentTools(server, conn);\n registerPullRequestTools(server, conn);\n registerSubtaskTools(server, conn);\n registerDependencyTools(server, conn);\n registerSuggestionTools(server, conn);\n registerChecklistTools(server, conn);\n registerWorkspaceTools(server, conn);\n registerLogTools(server, conn);\n}\n"],"mappings":"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","names":["server","conn","z","server","conn","projectId","z","server","conn","z","server","conn","z","server","conn","z","STATUS_ENUM","server","conn","z","server","conn","z","server","conn","z","server","conn","z","server","server","conn","z","z","conn","server","server","conn"]}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ConveyorConnection
3
- } from "./chunk-3HM7WTJR.js";
3
+ } from "./chunk-HRIOQERY.js";
4
4
  import {
5
5
  attachTunnel,
6
6
  runTunnel,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ConveyorConnection
4
- } from "./chunk-3HM7WTJR.js";
4
+ } from "./chunk-HRIOQERY.js";
5
5
  import {
6
6
  runTunnel
7
7
  } from "./chunk-N2XC2PGJ.js";
package/dist/tunnel.d.ts CHANGED
@@ -3,6 +3,12 @@ interface ConveyorMcpConfig {
3
3
  projectToken: string;
4
4
  projectId?: string;
5
5
  }
6
+ /**
7
+ * Canonical risk levels — kept in lockstep with `RISK_LEVELS` in
8
+ * `@project/shared` (conveyor-mcp is published standalone and does not depend on
9
+ * the shared package, so the vocabulary is duplicated here).
10
+ */
11
+ type RiskLevel = "critical" | "high" | "medium" | "low";
6
12
  /** A single PTY output frame broadcast on the `pty:data` room event. */
7
13
  interface PtyDataChunk {
8
14
  sessionId: string;
@@ -75,6 +81,13 @@ interface GcpLogQueryResult {
75
81
  scopedServices?: string[];
76
82
  error?: string;
77
83
  }
84
+ interface MoveCardResult {
85
+ cardId: string;
86
+ sourceProjectId: string;
87
+ destinationProjectId: string;
88
+ slug: string;
89
+ clearedFields: string[];
90
+ }
78
91
  declare class ConveyorConnection {
79
92
  private socket;
80
93
  private config;
@@ -143,15 +156,33 @@ declare class ConveyorConnection {
143
156
  projectId?: string;
144
157
  taskId: string;
145
158
  title?: string;
146
- description?: string;
147
159
  plan?: string;
148
- status?: string;
160
+ risk?: RiskLevel | null;
149
161
  assignedUserId?: string | null;
150
162
  subProjectId?: string | null;
151
163
  }): Promise<{
152
164
  id: string;
153
165
  status: string;
166
+ risk: RiskLevel | null;
167
+ assignedUserId: string | null;
154
168
  }>;
169
+ /** Guarded status transition used by the review tools (approve/request). */
170
+ transitionTaskStatus(params: {
171
+ projectId?: string;
172
+ taskId: string;
173
+ toStatus: string;
174
+ expectedFromStatus?: string;
175
+ risk?: RiskLevel;
176
+ }): Promise<{
177
+ id: string;
178
+ status: string;
179
+ risk: RiskLevel | null;
180
+ }>;
181
+ moveCard(params: {
182
+ projectId?: string;
183
+ taskId: string;
184
+ destinationProjectId: string;
185
+ }): Promise<MoveCardResult>;
155
186
  addReviewer(params: {
156
187
  projectId?: string;
157
188
  taskId: string;
@@ -271,10 +302,10 @@ declare class ConveyorConnection {
271
302
  color: string;
272
303
  }[]>;
273
304
  getProjectSummary(projectId?: string): Promise<unknown>;
274
- approveTask(taskId: string, projectId?: string): Promise<{
305
+ approveTask(taskId: string, projectId?: string, risk?: RiskLevel): Promise<{
275
306
  status: string;
276
307
  }>;
277
- requestChanges(taskId: string, feedback: string, projectId?: string): Promise<void>;
308
+ requestChanges(taskId: string, feedback: string, projectId?: string, risk?: RiskLevel): Promise<void>;
278
309
  approveAndMergePR(childTaskId: string, projectId?: string): Promise<{
279
310
  merged: boolean;
280
311
  childTaskId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rallycry/conveyor-mcp",
3
- "version": "4.2.2",
3
+ "version": "4.3.1",
4
4
  "description": "Conveyor MCP server for Claude Code PM integration",
5
5
  "keywords": [
6
6
  "claude",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/connection.ts"],"sourcesContent":["/* oxlint-disable max-lines -- central MCP socket client; split after service-call helpers are extracted */\nimport { io, type Socket } from \"socket.io-client\";\n\nexport interface ConveyorMcpConfig {\n apiUrl: string;\n projectToken: string;\n projectId?: string;\n}\n\n/** A single PTY output frame broadcast on the `pty:data` room event. */\nexport interface PtyDataChunk {\n sessionId: string;\n seq: number;\n data: string;\n cols?: number;\n rows?: number;\n}\n\n/** Ring-buffer snapshot returned by `ptyAttach` for catch-up replay. */\nexport interface PtyAttachSnapshot {\n sessionId: string;\n chunks: { seq: number; data: string }[];\n cols: number;\n rows: number;\n totalBytes: number;\n}\n\n/**\n * Result of `getActivePtySession`. `sessionId` is null until the cloud agent\n * has booted a PTY and produced at least one ring frame (readiness signal).\n */\nexport interface ActivePtySession {\n sessionId: string | null;\n cols?: number;\n rows?: number;\n}\n\nexport interface WorkspaceAttachInfo {\n taskId: string;\n sessionId: string;\n workspaceRoot: string;\n tunnelUrl: string;\n attachToken: string;\n expiresAt: string;\n previewPorts: Array<{ port: number; label: string }>;\n previewUrls: Record<string, string>;\n ssh?: {\n remotePort: number;\n preferredLocalPort: number;\n username: string;\n };\n}\n\n/** One Cloud Logging entry as returned by the API's queryProjectGcpLogs. */\nexport interface GcpLogEntry {\n timestamp: string;\n severity: string;\n message: string;\n resource: Record<string, string>;\n labels: Record<string, string>;\n resourceType?: string;\n insertId?: string;\n trace?: string;\n httpRequest?: { status?: number; method?: string; url?: string; latencyMs?: number };\n payload?: string;\n payloadTruncated?: boolean;\n}\n\nexport interface GcpLogQueryResult {\n entries: GcpLogEntry[];\n hasMore: boolean;\n nextPageToken?: string;\n scopedServices?: string[];\n error?: string;\n}\n\ntype SocketCallback = (response: { success: boolean; data?: unknown; error?: string }) => void;\n\nconst NO_PROJECT_SELECTED_MESSAGE =\n \"No Conveyor project selected. Pass projectId to this tool or configure CONVEYOR_PROJECT_ID.\";\n\n/** Auth failures never recover on retry — match them to fail fast with guidance. */\nconst AUTH_ERROR_RE = /token|unauthor|forbidden|not authenticated|invalid auth/i;\n\n/**\n * Turn a raw server error into an actionable message. Most errors pass through\n * unchanged; the common-but-opaque \"Insufficient permissions\" gets the missing\n * context about why (project role too low) and how to fix it.\n */\nfunction enrichToolError(error?: string, fallback?: string): string {\n const base = error ?? fallback ?? \"Request failed\";\n if (/insufficient permissions/i.test(base)) {\n return (\n `${base}: your Conveyor project role can't perform this action. ` +\n `Creating/updating tasks, builds, and PRs requires Moderate access or higher — ` +\n `ask a project admin to raise your role.`\n );\n }\n return base;\n}\n\nexport class ConveyorConnection {\n private socket: Socket | null = null;\n private config: ConveyorMcpConfig;\n\n constructor(config: ConveyorMcpConfig) {\n this.config = config;\n }\n\n get projectId(): string {\n return this.resolveProjectId();\n }\n\n private resolveProjectId(projectId?: string): string {\n const resolved = projectId ?? this.config.projectId;\n if (!resolved) throw new Error(NO_PROJECT_SELECTED_MESSAGE);\n return resolved;\n }\n\n private normalizeProjectList(response: unknown): unknown[] {\n if (Array.isArray(response)) return response;\n if (typeof response !== \"object\" || response === null) return [];\n const record = response as Record<string, unknown>;\n if (Array.isArray(record.items)) return record.items;\n if (Array.isArray(record.projects)) return record.projects;\n if (Array.isArray(record.data)) return record.data;\n return [];\n }\n\n connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n let settled = false;\n let attempts = 0;\n const maxAttempts = 15;\n\n this.socket = io(this.config.apiUrl, {\n auth: {\n projectToken: this.config.projectToken,\n runnerMode: \"project\",\n },\n transports: [\"websocket\"],\n reconnection: true,\n reconnectionAttempts: Infinity,\n reconnectionDelay: 2000,\n reconnectionDelayMax: 30000,\n randomizationFactor: 0.3,\n extraHeaders: { \"ngrok-skip-browser-warning\": \"true\" },\n });\n\n this.socket.on(\"connect\", () => {\n if (!settled) {\n settled = true;\n // Subscribe to project room for events\n this.socket?.emit(\"projectService:subscribe\", { id: this.config.projectId });\n resolve();\n }\n });\n\n this.socket.on(\"connect_error\", (err) => {\n const message = err?.message ?? \"unknown error\";\n // An auth rejection (e.g. \"Invalid project token\") will never succeed on\n // retry, so fail fast with an actionable message instead of silently\n // retrying for ~30s and then dying with a generic error.\n if (!settled && AUTH_ERROR_RE.test(message)) {\n settled = true;\n this.socket?.close();\n reject(\n new Error(\n `Conveyor rejected the connection: ${message}. The project token is ` +\n `likely invalid or expired — regenerate it in the web app ` +\n `(User Settings → Connect Claude Code) and update CONVEYOR_USER_TOKEN ` +\n `(or legacy CONVEYOR_PROJECT_TOKEN).`,\n ),\n );\n return;\n }\n attempts++;\n if (!settled && attempts >= maxAttempts) {\n settled = true;\n reject(new Error(`Failed to connect to ${this.config.apiUrl}: ${message}`));\n }\n });\n });\n }\n\n // ── Service method call (agentSessionService:*) ─────────────────────\n\n private call<T>(method: string, data: unknown, timeoutMs = 15_000): Promise<T> {\n const socket = this.socket;\n if (!socket) throw new Error(\"Not connected\");\n\n const TIMEOUT_MS = timeoutMs;\n\n return Promise.race([\n new Promise<T>((resolve, reject) => {\n socket.emit(`agentSessionService:${method}`, data, ((response: {\n success: boolean;\n data?: T;\n error?: string;\n }) => {\n if (response.success) {\n resolve(response.data as T);\n } else {\n reject(new Error(enrichToolError(response.error, `${method} failed`)));\n }\n }) as SocketCallback);\n }),\n new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(new Error(`Request timed out: ${method}`));\n }, TIMEOUT_MS);\n }),\n ]);\n }\n\n /**\n * Fire-and-forget emit (no ack). The quickdraw-core server method handler\n * invokes the ack callback via optional chaining, so omitting it still runs\n * the full auth/schema/ACL pipeline — it just skips the response round-trip.\n * Used for high-frequency PTY input/resize so each keystroke does not arm a\n * 15s timeout timer.\n */\n private emit(method: string, data: unknown): void {\n const socket = this.socket;\n if (!socket) throw new Error(\"Not connected\");\n socket.emit(`agentSessionService:${method}`, data);\n }\n\n private callService<T>(\n serviceName: string,\n method: string,\n data: unknown,\n timeoutMs = 15_000,\n ): Promise<T> {\n const socket = this.socket;\n if (!socket) throw new Error(\"Not connected\");\n return Promise.race([\n new Promise<T>((resolve, reject) => {\n socket.emit(`${serviceName}:${method}`, data, ((response: {\n success: boolean;\n data?: T;\n error?: string;\n }) => {\n if (response.success) {\n resolve(response.data as T);\n } else {\n reject(new Error(enrichToolError(response.error, `${method} failed`)));\n }\n }) as SocketCallback);\n }),\n new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(new Error(`Request timed out: ${serviceName}:${method}`));\n }, timeoutMs);\n }),\n ]);\n }\n\n // ── GCP Logs ────────────────────────────────────────────────────────\n\n queryGcpLogs(params: {\n projectId?: string;\n env?: \"prod\" | \"dev\" | \"claudespace\";\n severity?: string;\n services?: string[];\n sqlInstances?: string[];\n allServices?: boolean;\n search?: string;\n filter?: string;\n startTime?: string;\n endTime?: string;\n limit?: number;\n pageToken?: string;\n }): Promise<GcpLogQueryResult> {\n const { projectId, ...rest } = params;\n return this.call(\n \"queryProjectGcpLogs\",\n { projectId: this.resolveProjectId(projectId), ...rest },\n 30_000,\n );\n }\n\n // ── Task Queries ────────────────────────────────────────────────────\n\n listTasks(params: {\n projectId?: string;\n status?: string;\n assigneeId?: string;\n unassigned?: boolean;\n subProjectId?: string;\n limit?: number;\n }): Promise<unknown[]> {\n const { projectId, ...rest } = params;\n return this.call(\"listProjectTasks\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n getTask(taskId: string, projectId?: string): Promise<unknown> {\n return this.call(\"getProjectTask\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n });\n }\n\n getCardBySlug(slug: string, projectId?: string): Promise<unknown> {\n return this.call(\"getProjectTask\", {\n projectId: this.resolveProjectId(projectId),\n taskId: slug,\n });\n }\n\n searchTasks(params: {\n projectId?: string;\n tagNames?: string[];\n searchQuery?: string;\n statusFilters?: string[];\n typeFilters?: string[];\n assigneeId?: string;\n unassigned?: boolean;\n subProjectId?: string;\n limit?: number;\n }): Promise<unknown[]> {\n const { projectId, ...rest } = params;\n return this.call(\"searchProjectTasks\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n // ── Task Mutations ──────────────────────────────────────────────────\n\n createTask(params: {\n projectId?: string;\n title: string;\n description?: string;\n plan?: string;\n status?: string;\n subProjectId?: string;\n }): Promise<{ id: string; slug: string }> {\n const { projectId, ...rest } = params;\n return this.call(\"createProjectTask\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n updateTask(params: {\n projectId?: string;\n taskId: string;\n title?: string;\n description?: string;\n plan?: string;\n status?: string;\n assignedUserId?: string | null;\n subProjectId?: string | null;\n }): Promise<{ id: string; status: string }> {\n const { projectId, ...rest } = params;\n return this.call(\"updateProjectTask\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n // ── Reviewers & Members ─────────────────────────────────────────────\n\n addReviewer(params: {\n projectId?: string;\n taskId: string;\n userId: string;\n }): Promise<{ taskId: string; reviewers: Array<{ userId: string; name: string | null }> }> {\n const { projectId, ...rest } = params;\n return this.call(\"addProjectTaskReviewer\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n removeReviewer(params: {\n projectId?: string;\n taskId: string;\n userId: string;\n }): Promise<{ taskId: string; reviewers: Array<{ userId: string; name: string | null }> }> {\n const { projectId, ...rest } = params;\n return this.call(\"removeProjectTaskReviewer\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n listProjectMembers(\n projectId?: string,\n ): Promise<Array<{ userId: string; name: string | null; email: string; level: string }>> {\n return this.call(\"listProjectMembers\", {\n projectId: this.resolveProjectId(projectId),\n });\n }\n\n async listProjects(): Promise<unknown[]> {\n const response = await this.call(\"listAccessibleProjects\", { pageSize: 100 });\n return this.normalizeProjectList(response);\n }\n\n // ── Build Management ────────────────────────────────────────────────\n\n startBuild(taskId: string, projectId?: string): Promise<{ taskId: string; status: string }> {\n return this.call(\"startProjectBuild\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n });\n }\n\n stopBuild(taskId: string, projectId?: string): Promise<{ taskId: string; stopped: boolean }> {\n return this.call(\"stopProjectBuild\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n });\n }\n\n sleepTask(\n taskId: string,\n projectId?: string,\n ): Promise<{ taskId: string; codespaceStatus: string }> {\n return this.callService(\"cloudBuildService\", \"sleepCloudBuild\", {\n taskId,\n projectId: this.resolveProjectId(projectId),\n });\n }\n\n resumeTask(taskId: string, projectId?: string): Promise<{ status: string }> {\n return this.callService(\"cloudBuildService\", \"wakeCodespace\", {\n taskId,\n projectId: this.resolveProjectId(projectId),\n });\n }\n\n deleteTaskEnvironment(\n taskId: string,\n projectId?: string,\n ): Promise<{ taskId: string; status: string }> {\n return this.callService(\"cloudBuildService\", \"deleteTaskEnvironment\", {\n taskId,\n projectId: this.resolveProjectId(projectId),\n });\n }\n\n getBuildStatus(\n taskId: string,\n projectId?: string,\n ): Promise<{\n session: { status: string | null; agentRunnerStatus: string | null } | null;\n }> {\n // Uses getProjectTask and extracts the session field\n return this.call<Record<string, unknown>>(\"getProjectTask\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n }).then((task) => ({\n session:\n (task?.session as {\n status: string | null;\n agentRunnerStatus: string | null;\n }) ?? null,\n }));\n }\n\n getWorkspaceAttachInfo(taskId: string, sshPublicKey?: string): Promise<WorkspaceAttachInfo> {\n return this.callService(\"cloudBuildService\", \"getWorkspaceAttachInfo\", {\n taskId,\n sshPublicKey,\n });\n }\n\n // ── Chat ────────────────────────────────────────────────────────────\n\n getTaskChat(taskId: string, limit?: number, projectId?: string): Promise<unknown[]> {\n // Uses getProjectTask and extracts chatMessages\n return this.call<Record<string, unknown>>(\"getProjectTask\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n }).then((task) => {\n const messages = (task?.chatMessages ?? []) as unknown[];\n return limit ? messages.slice(-limit) : messages;\n });\n }\n\n postToTaskChat(\n taskId: string,\n content: string,\n projectId?: string,\n ): Promise<{ messageId: string }> {\n return this.call(\"postToProjectTaskChat\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n content,\n });\n }\n\n // ── CLI History ─────────────────────────────────────────────────────\n\n getTaskCli(\n taskId: string,\n limit?: number,\n source?: string,\n projectId?: string,\n ): Promise<{ type: string; data: Record<string, unknown>; timestamp: string }[]> {\n return this.call(\"getProjectTaskCli\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n limit,\n source,\n });\n }\n\n // ── Session / Pod State ─────────────────────────────────────────────\n\n getTaskSessions(\n taskId: string,\n projectId?: string,\n ): Promise<\n Array<{\n taskId: string;\n slug: string;\n title: string;\n type: string;\n status: string;\n reviewTargetTaskId: string | null;\n codeReviewStatus: string | null;\n codeReviewAttempts: number;\n workspaces: Array<{\n id: string;\n purpose: string;\n desiredState: string;\n observedState: string;\n branch: string | null;\n checkoutRef: string | null;\n createdAt: string;\n updatedAt: string;\n pod: { name: string; namespace: string; phase: string; imageUri: string | null } | null;\n sessions: Array<{\n id: string;\n role: string;\n mode: string;\n status: string;\n userId: string;\n leaseUntil: string | null;\n createdAt: string;\n }>;\n }>;\n sessions: Array<{\n id: string;\n provider: string;\n instanceName: string | null;\n status: string;\n agentRunnerStatus: string | null;\n lastHeartbeatAt: string | null;\n agentRunningAt: string | null;\n lastAgentEvent: string | null;\n deletionRequestedAt: string | null;\n deletionAttempts: number;\n createdAt: string;\n stoppedAt: string | null;\n }>;\n }>\n > {\n return this.call(\"getProjectTaskSessions\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n });\n }\n\n // ── Project Info ────────────────────────────────────────────────────\n\n listTags(projectId?: string): Promise<{ id: string; name: string; color: string }[]> {\n return this.call(\"listProjectTags\", {\n projectId: this.resolveProjectId(projectId),\n });\n }\n\n getProjectSummary(projectId?: string): Promise<unknown> {\n return this.call(\"getProjectSummary\", {\n projectId: this.resolveProjectId(projectId),\n });\n }\n\n // ── Review Flow ─────────────────────────────────────────────────────\n\n async approveTask(taskId: string, projectId?: string): Promise<{ status: string }> {\n const targetProjectId = this.resolveProjectId(projectId);\n // Determine next status based on current status\n const task = (await this.call(\"getProjectTask\", {\n projectId: targetProjectId,\n taskId,\n })) as { status: string } | null;\n\n if (!task) throw new Error(\"Task not found\");\n\n const nextStatus = task.status === \"ReviewPR\" ? \"ReviewDev\" : \"Complete\";\n\n const result = await this.updateTask({\n projectId: targetProjectId,\n taskId,\n status: nextStatus,\n });\n return { status: result.status };\n }\n\n async requestChanges(taskId: string, feedback: string, projectId?: string): Promise<void> {\n const targetProjectId = this.resolveProjectId(projectId);\n // Post feedback to task chat then move to InProgress\n await this.postToTaskChat(taskId, feedback, targetProjectId);\n await this.updateTask({ projectId: targetProjectId, taskId, status: \"InProgress\" });\n }\n\n approveAndMergePR(\n childTaskId: string,\n projectId?: string,\n ): Promise<{ merged: boolean; childTaskId: string; prNumber: number }> {\n return this.call(\"approveProjectMergePR\", {\n projectId: this.resolveProjectId(projectId),\n childTaskId,\n });\n }\n\n // ── File Attachments ────────────────────────────────────────────────\n\n listTaskFiles(taskId: string, projectId?: string): Promise<unknown[]> {\n return this.call(\"listProjectTaskFiles\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n });\n }\n\n getAttachment(\n taskId: string,\n fileId: string,\n opts?: { offset?: number; maxBytes?: number; projectId?: string },\n ): Promise<unknown> {\n const payload: Record<string, unknown> = {\n projectId: this.resolveProjectId(opts?.projectId),\n taskId,\n fileId,\n };\n if (opts?.offset !== undefined) payload.offset = opts.offset;\n if (opts?.maxBytes !== undefined) payload.maxBytes = opts.maxBytes;\n return this.call(\"getProjectAttachment\", payload);\n }\n\n requestFileUpload(\n taskId: string,\n params: { fileName: string; mimeType: string; fileSize: number; projectId?: string },\n ): Promise<{ fileId: string; uploadUrl: string }> {\n const { projectId, ...rest } = params;\n return this.call(\"requestProjectFileUpload\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n ...rest,\n });\n }\n\n confirmFileUpload(\n taskId: string,\n fileId: string,\n comment?: string,\n projectId?: string,\n ): Promise<{ fileId: string; fileName: string; downloadUrl?: string; messageId?: string }> {\n const payload: Record<string, unknown> = {\n projectId: this.resolveProjectId(projectId),\n taskId,\n fileId,\n };\n if (comment !== undefined) payload.comment = comment;\n // Confirm verifies the object in GCS before marking it uploaded — allow\n // extra headroom for the storage round-trips.\n return this.call(\"confirmProjectFileUpload\", payload, 30_000);\n }\n\n // ── Releases ────────────────────────────────────────────────────────\n\n createRelease(\n taskIds?: string[],\n projectId?: string,\n ): Promise<{ taskId: string; version: string }> {\n // Full releases create the release branch + PR against GitHub synchronously;\n // allow the same headroom as createPullRequest.\n return this.call(\n \"createProjectRelease\",\n { projectId: this.resolveProjectId(projectId), taskIds },\n 45_000,\n );\n }\n\n // ── Pull Requests ───────────────────────────────────────────────────\n\n createPullRequest(params: {\n projectId?: string;\n taskId: string;\n title: string;\n body: string;\n head?: string;\n base?: string;\n }): Promise<{ prNumber: number; prUrl: string }> {\n const { projectId, ...rest } = params;\n // PR creation makes several sequential GitHub API calls (token, create,\n // existing-PR lookup); allow more headroom than the default request timeout.\n return this.call(\n \"createProjectPullRequest\",\n { projectId: this.resolveProjectId(projectId), ...rest },\n 45_000,\n );\n }\n\n // ── Subtasks ────────────────────────────────────────────────────────\n\n createSubtask(params: {\n projectId?: string;\n parentTaskId: string;\n title: string;\n description?: string;\n plan?: string;\n ordinal?: number;\n storyPointValue?: number;\n followParentStatus?: boolean;\n dependsOn?: string[];\n }): Promise<{ id: string; slug: string }> {\n const { projectId, ...rest } = params;\n return this.call(\"createProjectSubtask\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n updateSubtask(params: {\n projectId?: string;\n subtaskId: string;\n title?: string;\n description?: string;\n plan?: string;\n status?: string;\n ordinal?: number;\n storyPointValue?: number;\n followParentStatus?: boolean;\n }): Promise<{ id: string; status: string }> {\n const { projectId, ...rest } = params;\n return this.call(\"updateProjectSubtask\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n listSubtasks(taskId: string, projectId?: string): Promise<unknown[]> {\n return this.call(\"listProjectSubtasks\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n });\n }\n\n deleteSubtask(subtaskId: string, projectId?: string): Promise<{ deleted: boolean }> {\n return this.call(\"deleteProjectSubtask\", {\n projectId: this.resolveProjectId(projectId),\n subtaskId,\n });\n }\n\n // ── Dependencies ────────────────────────────────────────────────────\n\n getDependencies(taskId: string, projectId?: string): Promise<unknown[]> {\n return this.call(\"getProjectTaskDependencies\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n });\n }\n\n addDependency(params: {\n projectId?: string;\n taskId: string;\n dependsOnSlugOrId: string;\n }): Promise<{ success: boolean }> {\n const { projectId, ...rest } = params;\n return this.call(\"addProjectTaskDependency\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n removeDependency(params: {\n projectId?: string;\n taskId: string;\n dependsOnSlugOrId: string;\n }): Promise<{ success: boolean }> {\n const { projectId, ...rest } = params;\n return this.call(\"removeProjectTaskDependency\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n // ── Manual Test Checklist ───────────────────────────────────────────\n\n listManualTests(\n taskId: string,\n projectId?: string,\n ): Promise<\n Array<{\n id: string;\n type: string;\n title: string;\n ordinal: number;\n createdAt: string;\n checked: boolean;\n failures: Array<{ userName: string | null; reason: string | null; createdAt: string }>;\n }>\n > {\n return this.call(\"listProjectManualTests\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n });\n }\n\n setManualTests(\n taskId: string,\n items: Array<{ title: string }>,\n projectId?: string,\n ): Promise<{ created: number; skipped: number }> {\n return this.call(\"setProjectManualTests\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n items,\n });\n }\n\n editManualTest(\n taskId: string,\n title: string,\n newTitle: string,\n projectId?: string,\n ): Promise<{ updated: boolean }> {\n return this.call(\"editProjectManualTest\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n title,\n newTitle,\n });\n }\n\n removeManualTest(\n taskId: string,\n title: string,\n projectId?: string,\n ): Promise<{ removed: boolean }> {\n return this.call(\"removeProjectManualTest\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n title,\n });\n }\n\n approveManualTest(\n taskId: string,\n title: string,\n projectId?: string,\n ): Promise<{ approved: boolean }> {\n return this.call(\"approveProjectManualTest\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n title,\n });\n }\n\n rejectManualTest(\n taskId: string,\n title: string,\n reason: string,\n projectId?: string,\n ): Promise<{ rejected: boolean }> {\n return this.call(\"rejectProjectManualTest\", {\n projectId: this.resolveProjectId(projectId),\n taskId,\n title,\n reason,\n });\n }\n\n queryManualTests(params: {\n projectId?: string;\n cardStatuses?: string[];\n testStatuses?: Array<\"open\" | \"approved\" | \"rejected\">;\n }): Promise<\n Array<{\n taskId: string;\n slug: string;\n title: string;\n status: string;\n tests: Array<{\n id: string;\n title: string;\n status: \"open\" | \"approved\" | \"rejected\";\n failures: Array<{ userName: string | null; reason: string | null; createdAt: string }>;\n }>;\n }>\n > {\n const { projectId, ...rest } = params;\n return this.call(\"queryProjectManualTests\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n // ── Suggestions ─────────────────────────────────────────────────────\n\n createSuggestion(params: {\n projectId?: string;\n title: string;\n description?: string;\n tagNames?: string[];\n }): Promise<{ id: string; merged: boolean; mergedIntoId?: string }> {\n const { projectId, ...rest } = params;\n return this.call(\"createProjectSuggestion\", {\n projectId: this.resolveProjectId(projectId),\n ...rest,\n });\n }\n\n // ── PTY Tunnel Relay (reuses the S2 pty:* envelope) ─────────────────\n\n /**\n * Poll target: returns the active cloud PTY session for a task once its ring\n * buffer has frames. `sessionId` is resolved server-side from `taskId` (never\n * accepted from the wire), preserving the one-active-session-per-task invariant.\n */\n getActivePtySession(taskId: string): Promise<ActivePtySession> {\n return this.call(\"getActivePtySession\", { taskId });\n }\n\n /** Fetch the ring-buffer snapshot for catch-up replay on (re)attach. */\n ptyAttach(sessionId: string): Promise<PtyAttachSnapshot> {\n return this.call(\"ptyAttach\", { sessionId });\n }\n\n /**\n * Join the session room so `pty:data` frames are delivered. Uses the standard\n * quickdraw-core subscribe envelope; \"Read\" is sufficient for output streaming.\n */\n subscribeToSession(sessionId: string): void {\n const socket = this.socket;\n if (!socket) throw new Error(\"Not connected\");\n socket.emit(\"agentSessionService:subscribe\", {\n entryId: sessionId,\n requiredLevel: \"Read\",\n });\n }\n\n /** Relay a stdin chunk to the cloud PTY (raw utf8, fire-and-forget). */\n ptyInput(sessionId: string, data: string): void {\n this.emit(\"ptyInput\", { sessionId, data });\n }\n\n /** Relay a terminal resize to the cloud PTY (fire-and-forget). */\n ptyResize(sessionId: string, cols: number, rows: number): void {\n this.emit(\"ptyResize\", { sessionId, cols, rows });\n }\n\n /** Subscribe to raw PTY output frames. Returns an unsubscribe function. */\n onPtyData(handler: (chunk: PtyDataChunk) => void): () => void {\n const socket = this.socket;\n if (!socket) throw new Error(\"Not connected\");\n socket.on(\"pty:data\", handler as (...args: unknown[]) => void);\n return () => {\n socket.off(\"pty:data\", handler as (...args: unknown[]) => void);\n };\n }\n\n // ── Connection lifecycle ────────────────────────────────────────────\n\n disconnect(): void {\n this.socket?.disconnect();\n this.socket = null;\n }\n}\n"],"mappings":"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","names":[]}