@dreb/coding-agent 2.61.1 → 2.61.2

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.
package/README.md CHANGED
@@ -414,7 +414,7 @@ Set `backgroundAgents.maxConcurrentSubagents` in `/settings`, dashboard Settings
414
414
 
415
415
  ### Waiting for GitHub CI
416
416
 
417
- Use `watch_github_ci` to monitor pull-request checks without asking the user to return later or constructing a polling loop. It runs `gh pr checks --watch --fail-fast`, defaults to the pull request for the current branch, accepts an optional PR number/URL/branch, and returns when checks pass or definitively fail. The call is cancellable and requires an installed, authenticated [GitHub CLI](https://cli.github.com/).
417
+ Use `watch_github_ci` to monitor pull-request checks without asking the user to return later or constructing a polling loop. It runs `gh pr checks --watch --fail-fast`, defaults to the pull request for the current branch, accepts an optional PR number/URL/branch, and returns when checks pass or definitively fail. After the watch completes, it makes a plain `gh pr checks` query so the model receives one clean final check listing rather than the repeated polling snapshots shown in live progress. The call is cancellable and requires an installed, authenticated [GitHub CLI](https://cli.github.com/).
418
418
 
419
419
  The separate `wait` tool is an immediate no-op used when explicitly told to wait or while background subagents are running. It does not monitor CI and must not be used as a sleep or delay.
420
420
 
@@ -1 +1 @@
1
- {"version":3,"file":"watch-github-ci.d.ts","sourceRoot":"","sources":["../../../src/core/tools/watch-github-ci.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,mBAAmB,CAAC;AAGtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAK7D,QAAA,MAAM,mBAAmB;;EAOvB,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAExE,MAAM,WAAW,wBAAwB;IACxC,MAAM,EAAE,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,CACL,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE;QACR,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;KACvB,KACG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,wBAAwB;IACxC,UAAU,CAAC,EAAE,kBAAkB,CAAC;CAChC;AAgCD,wBAAgB,6BAA6B,IAAI,kBAAkB,CA0ClE;AAYD,wBAAgB,iCAAiC,CAChD,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,wBAAwB,GAChC,cAAc,CAAC,OAAO,mBAAmB,EAAE,wBAAwB,CAAC,CAsHtE;AAED,wBAAgB,uBAAuB,CACtC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,wBAAwB,GAChC,SAAS,CAAC,OAAO,mBAAmB,CAAC,CAEvC;AAED,eAAO,MAAM,2BAA2B;;kCAAmD,CAAC;AAC5F,eAAO,MAAM,iBAAiB;;QAAyC,CAAC","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport type { AgentTool } from \"@dreb/agent-core\";\nimport { type Static, Type } from \"@sinclair/typebox\";\nimport { waitForChildProcess } from \"../../utils/child-process.js\";\nimport { getShellEnv, killProcessTree } from \"../../utils/shell.js\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { renderTerminalOutput } from \"./terminal-render.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\nimport { DEFAULT_MAX_BYTES, truncateTail } from \"./truncate.js\";\n\nconst watchGithubCiSchema = Type.Object({\n\tpr: Type.Optional(\n\t\tType.String({\n\t\t\tdescription:\n\t\t\t\t\"Optional pull request number, URL, or branch. Omit to use the pull request for the current branch.\",\n\t\t}),\n\t),\n});\n\nexport type WatchGithubCiToolInput = Static<typeof watchGithubCiSchema>;\n\nexport interface WatchGithubCiToolDetails {\n\tstatus: \"watching\" | \"passed\" | \"failed\";\n\texitCode?: number;\n\toutputTruncated: boolean;\n}\n\nexport interface GithubCiOperations {\n\texec: (\n\t\targs: readonly string[],\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tsignal?: AbortSignal;\n\t\t\tenv: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<{ exitCode: number | null }>;\n}\n\nexport interface WatchGithubCiToolOptions {\n\toperations?: GithubCiOperations;\n}\n\n/**\n * Substrings (matched case-insensitively) that identify a `gh pr checks` CLI-level\n * failure rather than a real failed-check result. `gh pr checks` exits 1 for both,\n * and `--json` is incompatible with `--watch`, so the captured output is the only\n * way to tell them apart. These signatures are specific enough that they will not\n * appear in a normal check-status table.\n */\nconst GH_CLI_FAILURE_SIGNATURES = [\n\t\"no pull requests found\",\n\t\"could not resolve to a pullrequest\",\n\t\"failed to run git\",\n\t\"not a git repository\",\n\t\"http 401\",\n\t\"bad credentials\",\n\t\"could not parse\",\n\t\"invalid pull request\",\n\t\"authentication required\",\n\t\"could not find repository\",\n];\n\nfunction detectGhCliFailure(output: string): string | null {\n\tconst lower = output.toLowerCase();\n\tfor (const signature of GH_CLI_FAILURE_SIGNATURES) {\n\t\tif (lower.includes(signature)) {\n\t\t\treturn signature;\n\t\t}\n\t}\n\treturn null;\n}\n\nexport function createLocalGithubCiOperations(): GithubCiOperations {\n\treturn {\n\t\texec: (args, cwd, { onData, signal, env }) =>\n\t\t\tnew Promise((resolve, reject) => {\n\t\t\t\tif (!existsSync(cwd)) {\n\t\t\t\t\treject(new Error(`Working directory does not exist: ${cwd}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst child = spawn(\"gh\", [...args], {\n\t\t\t\t\tcwd,\n\t\t\t\t\tdetached: true,\n\t\t\t\t\tenv,\n\t\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\t});\n\t\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\t\tchild.stderr?.on(\"data\", onData);\n\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t\t};\n\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\t\t\twaitForChildProcess(child)\n\t\t\t\t\t.then((exitCode) => {\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\treject(new Error(\"aborted\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresolve({ exitCode });\n\t\t\t\t\t})\n\t\t\t\t\t.catch((error) => {\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\treject(error);\n\t\t\t\t\t});\n\t\t\t}),\n\t};\n}\n\nfunction formatOutput(chunks: readonly Buffer[], omittedEarlierOutput: boolean): { text: string; truncated: boolean } {\n\tconst rendered = renderTerminalOutput(Buffer.concat(chunks).toString(\"utf-8\"));\n\tconst truncation = truncateTail(rendered);\n\tconst prefix = omittedEarlierOutput ? \"[Earlier watch output omitted]\\n\" : \"\";\n\treturn {\n\t\ttext: `${prefix}${truncation.content || \"(no output)\"}`,\n\t\ttruncated: omittedEarlierOutput || truncation.truncated,\n\t};\n}\n\nexport function createWatchGithubCiToolDefinition(\n\tcwd: string,\n\toptions?: WatchGithubCiToolOptions,\n): ToolDefinition<typeof watchGithubCiSchema, WatchGithubCiToolDetails> {\n\tconst operations = options?.operations ?? createLocalGithubCiOperations();\n\n\treturn {\n\t\tname: \"watch_github_ci\",\n\t\tlabel: \"watch GitHub CI\",\n\t\tdescription:\n\t\t\t\"Watch GitHub pull-request checks until they pass or fail. Uses the current branch's pull request by default, or an optional pull request number, URL, or branch. Returns the final GitHub CLI output without requiring user input.\",\n\t\tpromptSnippet: \"Watch GitHub pull-request CI until checks pass or fail\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use `watch_github_ci` to wait for GitHub pull-request checks instead of asking the user, polling with repeated commands, sleeping, or using `wait`\",\n\t\t\t\"`watch_github_ci` blocks until the selected pull request's checks pass or fail; omit `pr` to use the current branch's pull request\",\n\t\t],\n\t\tparameters: watchGithubCiSchema,\n\t\tasync execute(_toolCallId, params, signal, onUpdate) {\n\t\t\tconst selector = params.pr?.trim();\n\t\t\tif (params.pr !== undefined && !selector) {\n\t\t\t\tthrow new Error(\"Pull request selector must not be blank.\");\n\t\t\t}\n\t\t\tif (selector?.startsWith(\"-\")) {\n\t\t\t\tthrow new Error(\"Pull request selector must not begin with '-'.\");\n\t\t\t}\n\n\t\t\tconst args = [\"pr\", \"checks\", ...(selector ? [selector] : []), \"--watch\", \"--fail-fast\"];\n\t\t\tconst chunks: Buffer[] = [];\n\t\t\tlet chunksBytes = 0;\n\t\t\tlet omittedEarlierOutput = false;\n\t\t\tlet outputTruncated = false;\n\t\t\tconst maxBufferedBytes = DEFAULT_MAX_BYTES * 2;\n\n\t\t\tconst details = (status: WatchGithubCiToolDetails[\"status\"], exitCode?: number) => ({\n\t\t\t\tstatus,\n\t\t\t\texitCode,\n\t\t\t\toutputTruncated,\n\t\t\t});\n\t\t\tconst currentOutput = (): string => {\n\t\t\t\tconst formatted = formatOutput(chunks, omittedEarlierOutput);\n\t\t\t\toutputTruncated = formatted.truncated;\n\t\t\t\treturn formatted.text;\n\t\t\t};\n\t\t\tconst onData = (data: Buffer) => {\n\t\t\t\tchunks.push(data);\n\t\t\t\tchunksBytes += data.length;\n\t\t\t\twhile (chunksBytes > maxBufferedBytes) {\n\t\t\t\t\tconst excess = chunksBytes - maxBufferedBytes;\n\t\t\t\t\tconst first = chunks[0];\n\t\t\t\t\tif (first.length <= excess) {\n\t\t\t\t\t\tchunks.shift();\n\t\t\t\t\t\tchunksBytes -= first.length;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tchunks[0] = first.subarray(excess);\n\t\t\t\t\t\tchunksBytes -= excess;\n\t\t\t\t\t}\n\t\t\t\t\tomittedEarlierOutput = true;\n\t\t\t\t}\n\t\t\t\tonUpdate?.({\n\t\t\t\t\tcontent: [{ type: \"text\", text: currentOutput() }],\n\t\t\t\t\tdetails: details(\"watching\"),\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tonUpdate?.({ content: [], details: details(\"watching\") });\n\n\t\t\tlet exitCode: number | null;\n\t\t\ttry {\n\t\t\t\t({ exitCode } = await operations.exec(args, cwd, {\n\t\t\t\t\tonData,\n\t\t\t\t\tsignal,\n\t\t\t\t\tenv: {\n\t\t\t\t\t\t...getShellEnv(),\n\t\t\t\t\t\tGH_PAGER: \"cat\",\n\t\t\t\t\t\tGH_EDITOR: \"cat\",\n\t\t\t\t\t\tNO_COLOR: \"1\",\n\t\t\t\t\t},\n\t\t\t\t}));\n\t\t\t} catch (error) {\n\t\t\t\tconst output = chunks.length > 0 ? `${currentOutput()}\\n\\n` : \"\";\n\t\t\t\tif (error instanceof Error && error.message === \"aborted\") {\n\t\t\t\t\tthrow new Error(`${output}GitHub CI watch aborted.`);\n\t\t\t\t}\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new Error(`${output}GitHub CI watch could not run: ${message}`);\n\t\t\t}\n\n\t\t\tconst output = currentOutput();\n\t\t\tif (exitCode === 0) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `GitHub CI checks passed.\\n\\n${output}` }],\n\t\t\t\t\tdetails: details(\"passed\", exitCode),\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (exitCode === 1) {\n\t\t\t\tconst cliFailure = detectGhCliFailure(output);\n\t\t\t\tif (cliFailure !== null) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`GitHub CI watch could not query checks: the GitHub CLI reported an error (matched \"${cliFailure}\"). This is a CLI-level failure such as a bad pull-request selector, no pull request for the branch, a missing repository, or an authentication problem — not a failed-check result. Re-check the selector and \\`gh auth status\\`.\\n\\n${output}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `GitHub CI checks did not pass. The GitHub CLI exited with code 1.\\n\\n${output}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: details(\"failed\", exitCode),\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (exitCode === 8) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`GitHub CI watch exited while checks were still pending (exit code 8); refusing to treat this as a terminal result.\\n\\n${output}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow new Error(\n\t\t\t\t`GitHub CI watch exited unexpectedly${exitCode === null ? \" without an exit code\" : ` with code ${exitCode}`}.\\n\\n${output}`,\n\t\t\t);\n\t\t},\n\t};\n}\n\nexport function createWatchGithubCiTool(\n\tcwd: string,\n\toptions?: WatchGithubCiToolOptions,\n): AgentTool<typeof watchGithubCiSchema> {\n\treturn wrapToolDefinition(createWatchGithubCiToolDefinition(cwd, options));\n}\n\nexport const watchGithubCiToolDefinition = createWatchGithubCiToolDefinition(process.cwd());\nexport const watchGithubCiTool = createWatchGithubCiTool(process.cwd());\n"]}
1
+ {"version":3,"file":"watch-github-ci.d.ts","sourceRoot":"","sources":["../../../src/core/tools/watch-github-ci.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,mBAAmB,CAAC;AAGtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAK7D,QAAA,MAAM,mBAAmB;;EAOvB,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAExE,MAAM,WAAW,wBAAwB;IACxC,MAAM,EAAE,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,CACL,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE;QACR,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;KACvB,KACG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,wBAAwB;IACxC,UAAU,CAAC,EAAE,kBAAkB,CAAC;CAChC;AAgCD,wBAAgB,6BAA6B,IAAI,kBAAkB,CA0ClE;AA8CD,wBAAgB,iCAAiC,CAChD,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,wBAAwB,GAChC,cAAc,CAAC,OAAO,mBAAmB,EAAE,wBAAwB,CAAC,CA6ItE;AAED,wBAAgB,uBAAuB,CACtC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,wBAAwB,GAChC,SAAS,CAAC,OAAO,mBAAmB,CAAC,CAEvC;AAED,eAAO,MAAM,2BAA2B;;kCAAmD,CAAC;AAC5F,eAAO,MAAM,iBAAiB;;QAAyC,CAAC","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport type { AgentTool } from \"@dreb/agent-core\";\nimport { type Static, Type } from \"@sinclair/typebox\";\nimport { waitForChildProcess } from \"../../utils/child-process.js\";\nimport { getShellEnv, killProcessTree } from \"../../utils/shell.js\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { renderTerminalOutput } from \"./terminal-render.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\nimport { DEFAULT_MAX_BYTES, truncateTail } from \"./truncate.js\";\n\nconst watchGithubCiSchema = Type.Object({\n\tpr: Type.Optional(\n\t\tType.String({\n\t\t\tdescription:\n\t\t\t\t\"Optional pull request number, URL, or branch. Omit to use the pull request for the current branch.\",\n\t\t}),\n\t),\n});\n\nexport type WatchGithubCiToolInput = Static<typeof watchGithubCiSchema>;\n\nexport interface WatchGithubCiToolDetails {\n\tstatus: \"watching\" | \"passed\" | \"failed\";\n\texitCode?: number;\n\toutputTruncated: boolean;\n}\n\nexport interface GithubCiOperations {\n\texec: (\n\t\targs: readonly string[],\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tsignal?: AbortSignal;\n\t\t\tenv: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<{ exitCode: number | null }>;\n}\n\nexport interface WatchGithubCiToolOptions {\n\toperations?: GithubCiOperations;\n}\n\n/**\n * Substrings (matched case-insensitively) that identify a `gh pr checks` CLI-level\n * failure rather than a real failed-check result. `gh pr checks` exits 1 for both,\n * and `--json` is incompatible with `--watch`, so the captured output is the only\n * way to tell them apart. These signatures are specific enough that they will not\n * appear in a normal check-status table.\n */\nconst GH_CLI_FAILURE_SIGNATURES = [\n\t\"no pull requests found\",\n\t\"could not resolve to a pullrequest\",\n\t\"failed to run git\",\n\t\"not a git repository\",\n\t\"http 401\",\n\t\"bad credentials\",\n\t\"could not parse\",\n\t\"invalid pull request\",\n\t\"authentication required\",\n\t\"could not find repository\",\n];\n\nfunction detectGhCliFailure(output: string): string | null {\n\tconst lower = output.toLowerCase();\n\tfor (const signature of GH_CLI_FAILURE_SIGNATURES) {\n\t\tif (lower.includes(signature)) {\n\t\t\treturn signature;\n\t\t}\n\t}\n\treturn null;\n}\n\nexport function createLocalGithubCiOperations(): GithubCiOperations {\n\treturn {\n\t\texec: (args, cwd, { onData, signal, env }) =>\n\t\t\tnew Promise((resolve, reject) => {\n\t\t\t\tif (!existsSync(cwd)) {\n\t\t\t\t\treject(new Error(`Working directory does not exist: ${cwd}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst child = spawn(\"gh\", [...args], {\n\t\t\t\t\tcwd,\n\t\t\t\t\tdetached: true,\n\t\t\t\t\tenv,\n\t\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\t});\n\t\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\t\tchild.stderr?.on(\"data\", onData);\n\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t\t};\n\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\t\t\twaitForChildProcess(child)\n\t\t\t\t\t.then((exitCode) => {\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\treject(new Error(\"aborted\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresolve({ exitCode });\n\t\t\t\t\t})\n\t\t\t\t\t.catch((error) => {\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\treject(error);\n\t\t\t\t\t});\n\t\t\t}),\n\t};\n}\n\ninterface OutputBuffer {\n\tappend(data: Buffer): void;\n\tformat(): { text: string; truncated: boolean };\n\thasOutput(): boolean;\n}\n\nfunction createOutputBuffer(omittedPrefix: string): OutputBuffer {\n\tconst chunks: Buffer[] = [];\n\tlet chunksBytes = 0;\n\tlet omittedEarlierOutput = false;\n\tconst maxBufferedBytes = DEFAULT_MAX_BYTES * 2;\n\n\treturn {\n\t\tappend(data) {\n\t\t\tchunks.push(data);\n\t\t\tchunksBytes += data.length;\n\t\t\twhile (chunksBytes > maxBufferedBytes) {\n\t\t\t\tconst excess = chunksBytes - maxBufferedBytes;\n\t\t\t\tconst first = chunks[0];\n\t\t\t\tif (first.length <= excess) {\n\t\t\t\t\tchunks.shift();\n\t\t\t\t\tchunksBytes -= first.length;\n\t\t\t\t} else {\n\t\t\t\t\tchunks[0] = first.subarray(excess);\n\t\t\t\t\tchunksBytes -= excess;\n\t\t\t\t}\n\t\t\t\tomittedEarlierOutput = true;\n\t\t\t}\n\t\t},\n\t\tformat() {\n\t\t\tconst rendered = renderTerminalOutput(Buffer.concat(chunks).toString(\"utf-8\"));\n\t\t\tconst truncation = truncateTail(rendered);\n\t\t\tconst prefix = omittedEarlierOutput ? `${omittedPrefix}\\n` : \"\";\n\t\t\treturn {\n\t\t\t\ttext: `${prefix}${truncation.content || \"(no output)\"}`,\n\t\t\t\ttruncated: omittedEarlierOutput || truncation.truncated,\n\t\t\t};\n\t\t},\n\t\thasOutput() {\n\t\t\treturn chunks.length > 0;\n\t\t},\n\t};\n}\n\nexport function createWatchGithubCiToolDefinition(\n\tcwd: string,\n\toptions?: WatchGithubCiToolOptions,\n): ToolDefinition<typeof watchGithubCiSchema, WatchGithubCiToolDetails> {\n\tconst operations = options?.operations ?? createLocalGithubCiOperations();\n\n\treturn {\n\t\tname: \"watch_github_ci\",\n\t\tlabel: \"watch GitHub CI\",\n\t\tdescription:\n\t\t\t\"Watch GitHub pull-request checks until they pass or fail. Uses the current branch's pull request by default, or an optional pull request number, URL, or branch. Returns the final GitHub CLI output without requiring user input.\",\n\t\tpromptSnippet: \"Watch GitHub pull-request CI until checks pass or fail\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use `watch_github_ci` to wait for GitHub pull-request checks instead of asking the user, polling with repeated commands, sleeping, or using `wait`\",\n\t\t\t\"`watch_github_ci` blocks until the selected pull request's checks pass or fail; omit `pr` to use the current branch's pull request\",\n\t\t],\n\t\tparameters: watchGithubCiSchema,\n\t\tasync execute(_toolCallId, params, signal, onUpdate) {\n\t\t\tconst selector = params.pr?.trim();\n\t\t\tif (params.pr !== undefined && !selector) {\n\t\t\t\tthrow new Error(\"Pull request selector must not be blank.\");\n\t\t\t}\n\t\t\tif (selector?.startsWith(\"-\")) {\n\t\t\t\tthrow new Error(\"Pull request selector must not begin with '-'.\");\n\t\t\t}\n\n\t\t\tconst watchArgs = [\"pr\", \"checks\", ...(selector ? [selector] : []), \"--watch\", \"--fail-fast\"];\n\t\t\tconst finalArgs = [\"pr\", \"checks\", ...(selector ? [selector] : [])];\n\t\t\tconst env = {\n\t\t\t\t...getShellEnv(),\n\t\t\t\tGH_PAGER: \"cat\",\n\t\t\t\tGH_EDITOR: \"cat\",\n\t\t\t\tNO_COLOR: \"1\",\n\t\t\t};\n\t\t\tconst details = (status: WatchGithubCiToolDetails[\"status\"], outputTruncated: boolean, exitCode?: number) => ({\n\t\t\t\tstatus,\n\t\t\t\texitCode,\n\t\t\t\toutputTruncated,\n\t\t\t});\n\n\t\t\tconst watchOutput = createOutputBuffer(\"[Earlier watch output omitted]\");\n\t\t\tconst onWatchData = (data: Buffer) => {\n\t\t\t\twatchOutput.append(data);\n\t\t\t\tconst formatted = watchOutput.format();\n\t\t\t\tonUpdate?.({\n\t\t\t\t\tcontent: [{ type: \"text\", text: formatted.text }],\n\t\t\t\t\tdetails: details(\"watching\", formatted.truncated),\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tonUpdate?.({ content: [], details: details(\"watching\", false) });\n\n\t\t\tlet watchExitCode: number | null;\n\t\t\ttry {\n\t\t\t\t({ exitCode: watchExitCode } = await operations.exec(watchArgs, cwd, {\n\t\t\t\t\tonData: onWatchData,\n\t\t\t\t\tsignal,\n\t\t\t\t\tenv,\n\t\t\t\t}));\n\t\t\t} catch (error) {\n\t\t\t\tconst output = watchOutput.hasOutput() ? `${watchOutput.format().text}\\n\\n` : \"\";\n\t\t\t\tif (error instanceof Error && error.message === \"aborted\") {\n\t\t\t\t\tthrow new Error(`${output}GitHub CI watch aborted.`);\n\t\t\t\t}\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new Error(`${output}GitHub CI watch could not run: ${message}`);\n\t\t\t}\n\n\t\t\tconst formattedWatchOutput = watchOutput.format();\n\t\t\tif (watchExitCode === 1) {\n\t\t\t\tconst cliFailure = detectGhCliFailure(formattedWatchOutput.text);\n\t\t\t\tif (cliFailure !== null) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`GitHub CI watch could not query checks: the GitHub CLI reported an error (matched \"${cliFailure}\"). This is a CLI-level failure such as a bad pull-request selector, no pull request for the branch, a missing repository, or an authentication problem — not a failed-check result. Re-check the selector and \\`gh auth status\\`.\\n\\n${formattedWatchOutput.text}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else if (watchExitCode === 8) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`GitHub CI watch exited while checks were still pending (exit code 8); refusing to treat this as a terminal result.\\n\\n${formattedWatchOutput.text}`,\n\t\t\t\t);\n\t\t\t} else if (watchExitCode !== 0) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`GitHub CI watch exited unexpectedly${watchExitCode === null ? \" without an exit code\" : ` with code ${watchExitCode}`}.\\n\\n${formattedWatchOutput.text}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst finalOutput = createOutputBuffer(\"[Earlier final checks output omitted]\");\n\t\t\tlet finalExitCode: number | null;\n\t\t\ttry {\n\t\t\t\t({ exitCode: finalExitCode } = await operations.exec(finalArgs, cwd, {\n\t\t\t\t\tonData: (data) => finalOutput.append(data),\n\t\t\t\t\tsignal,\n\t\t\t\t\tenv,\n\t\t\t\t}));\n\t\t\t} catch (error) {\n\t\t\t\tconst output = finalOutput.hasOutput() ? `${finalOutput.format().text}\\n\\n` : \"\";\n\t\t\t\tif (error instanceof Error && error.message === \"aborted\") {\n\t\t\t\t\tthrow new Error(`${output}GitHub CI final checks query aborted.`);\n\t\t\t\t}\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new Error(`${output}GitHub CI final checks query could not run: ${message}`);\n\t\t\t}\n\n\t\t\tconst formattedFinalOutput = finalOutput.format();\n\t\t\tif (finalExitCode === 1) {\n\t\t\t\tconst cliFailure = detectGhCliFailure(formattedFinalOutput.text);\n\t\t\t\tif (cliFailure !== null) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`GitHub CI final checks query failed: the GitHub CLI reported an error (matched \"${cliFailure}\"). Re-check the selector and \\`gh auth status\\`.\\n\\n${formattedFinalOutput.text}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else if (finalExitCode === 8) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`GitHub CI final checks query found checks still pending (exit code 8) after the watch reported a terminal result.\\n\\n${formattedFinalOutput.text}`,\n\t\t\t\t);\n\t\t\t} else if (finalExitCode !== 0) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`GitHub CI final checks query exited unexpectedly${finalExitCode === null ? \" without an exit code\" : ` with code ${finalExitCode}`}.\\n\\n${formattedFinalOutput.text}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (watchExitCode !== finalExitCode) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`GitHub CI status changed between watch completion (exit code ${watchExitCode}) and the final checks query (exit code ${finalExitCode}); refusing to report a contradictory result.\\n\\n${formattedFinalOutput.text}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (finalExitCode === 0) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `GitHub CI checks passed.\\n\\n${formattedFinalOutput.text}` }],\n\t\t\t\t\tdetails: details(\"passed\", formattedFinalOutput.truncated, finalExitCode),\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `GitHub CI checks did not pass. The GitHub CLI exited with code 1.\\n\\n${formattedFinalOutput.text}`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdetails: details(\"failed\", formattedFinalOutput.truncated, finalExitCode),\n\t\t\t};\n\t\t},\n\t};\n}\n\nexport function createWatchGithubCiTool(\n\tcwd: string,\n\toptions?: WatchGithubCiToolOptions,\n): AgentTool<typeof watchGithubCiSchema> {\n\treturn wrapToolDefinition(createWatchGithubCiToolDefinition(cwd, options));\n}\n\nexport const watchGithubCiToolDefinition = createWatchGithubCiToolDefinition(process.cwd());\nexport const watchGithubCiTool = createWatchGithubCiTool(process.cwd());\n"]}
@@ -79,13 +79,41 @@ export function createLocalGithubCiOperations() {
79
79
  }),
80
80
  };
81
81
  }
82
- function formatOutput(chunks, omittedEarlierOutput) {
83
- const rendered = renderTerminalOutput(Buffer.concat(chunks).toString("utf-8"));
84
- const truncation = truncateTail(rendered);
85
- const prefix = omittedEarlierOutput ? "[Earlier watch output omitted]\n" : "";
82
+ function createOutputBuffer(omittedPrefix) {
83
+ const chunks = [];
84
+ let chunksBytes = 0;
85
+ let omittedEarlierOutput = false;
86
+ const maxBufferedBytes = DEFAULT_MAX_BYTES * 2;
86
87
  return {
87
- text: `${prefix}${truncation.content || "(no output)"}`,
88
- truncated: omittedEarlierOutput || truncation.truncated,
88
+ append(data) {
89
+ chunks.push(data);
90
+ chunksBytes += data.length;
91
+ while (chunksBytes > maxBufferedBytes) {
92
+ const excess = chunksBytes - maxBufferedBytes;
93
+ const first = chunks[0];
94
+ if (first.length <= excess) {
95
+ chunks.shift();
96
+ chunksBytes -= first.length;
97
+ }
98
+ else {
99
+ chunks[0] = first.subarray(excess);
100
+ chunksBytes -= excess;
101
+ }
102
+ omittedEarlierOutput = true;
103
+ }
104
+ },
105
+ format() {
106
+ const rendered = renderTerminalOutput(Buffer.concat(chunks).toString("utf-8"));
107
+ const truncation = truncateTail(rendered);
108
+ const prefix = omittedEarlierOutput ? `${omittedPrefix}\n` : "";
109
+ return {
110
+ text: `${prefix}${truncation.content || "(no output)"}`,
111
+ truncated: omittedEarlierOutput || truncation.truncated,
112
+ };
113
+ },
114
+ hasOutput() {
115
+ return chunks.length > 0;
116
+ },
89
117
  };
90
118
  }
91
119
  export function createWatchGithubCiToolDefinition(cwd, options) {
@@ -108,91 +136,106 @@ export function createWatchGithubCiToolDefinition(cwd, options) {
108
136
  if (selector?.startsWith("-")) {
109
137
  throw new Error("Pull request selector must not begin with '-'.");
110
138
  }
111
- const args = ["pr", "checks", ...(selector ? [selector] : []), "--watch", "--fail-fast"];
112
- const chunks = [];
113
- let chunksBytes = 0;
114
- let omittedEarlierOutput = false;
115
- let outputTruncated = false;
116
- const maxBufferedBytes = DEFAULT_MAX_BYTES * 2;
117
- const details = (status, exitCode) => ({
139
+ const watchArgs = ["pr", "checks", ...(selector ? [selector] : []), "--watch", "--fail-fast"];
140
+ const finalArgs = ["pr", "checks", ...(selector ? [selector] : [])];
141
+ const env = {
142
+ ...getShellEnv(),
143
+ GH_PAGER: "cat",
144
+ GH_EDITOR: "cat",
145
+ NO_COLOR: "1",
146
+ };
147
+ const details = (status, outputTruncated, exitCode) => ({
118
148
  status,
119
149
  exitCode,
120
150
  outputTruncated,
121
151
  });
122
- const currentOutput = () => {
123
- const formatted = formatOutput(chunks, omittedEarlierOutput);
124
- outputTruncated = formatted.truncated;
125
- return formatted.text;
126
- };
127
- const onData = (data) => {
128
- chunks.push(data);
129
- chunksBytes += data.length;
130
- while (chunksBytes > maxBufferedBytes) {
131
- const excess = chunksBytes - maxBufferedBytes;
132
- const first = chunks[0];
133
- if (first.length <= excess) {
134
- chunks.shift();
135
- chunksBytes -= first.length;
136
- }
137
- else {
138
- chunks[0] = first.subarray(excess);
139
- chunksBytes -= excess;
140
- }
141
- omittedEarlierOutput = true;
142
- }
152
+ const watchOutput = createOutputBuffer("[Earlier watch output omitted]");
153
+ const onWatchData = (data) => {
154
+ watchOutput.append(data);
155
+ const formatted = watchOutput.format();
143
156
  onUpdate?.({
144
- content: [{ type: "text", text: currentOutput() }],
145
- details: details("watching"),
157
+ content: [{ type: "text", text: formatted.text }],
158
+ details: details("watching", formatted.truncated),
146
159
  });
147
160
  };
148
- onUpdate?.({ content: [], details: details("watching") });
149
- let exitCode;
161
+ onUpdate?.({ content: [], details: details("watching", false) });
162
+ let watchExitCode;
150
163
  try {
151
- ({ exitCode } = await operations.exec(args, cwd, {
152
- onData,
164
+ ({ exitCode: watchExitCode } = await operations.exec(watchArgs, cwd, {
165
+ onData: onWatchData,
153
166
  signal,
154
- env: {
155
- ...getShellEnv(),
156
- GH_PAGER: "cat",
157
- GH_EDITOR: "cat",
158
- NO_COLOR: "1",
159
- },
167
+ env,
160
168
  }));
161
169
  }
162
170
  catch (error) {
163
- const output = chunks.length > 0 ? `${currentOutput()}\n\n` : "";
171
+ const output = watchOutput.hasOutput() ? `${watchOutput.format().text}\n\n` : "";
164
172
  if (error instanceof Error && error.message === "aborted") {
165
173
  throw new Error(`${output}GitHub CI watch aborted.`);
166
174
  }
167
175
  const message = error instanceof Error ? error.message : String(error);
168
176
  throw new Error(`${output}GitHub CI watch could not run: ${message}`);
169
177
  }
170
- const output = currentOutput();
171
- if (exitCode === 0) {
172
- return {
173
- content: [{ type: "text", text: `GitHub CI checks passed.\n\n${output}` }],
174
- details: details("passed", exitCode),
175
- };
178
+ const formattedWatchOutput = watchOutput.format();
179
+ if (watchExitCode === 1) {
180
+ const cliFailure = detectGhCliFailure(formattedWatchOutput.text);
181
+ if (cliFailure !== null) {
182
+ throw new Error(`GitHub CI watch could not query checks: the GitHub CLI reported an error (matched "${cliFailure}"). This is a CLI-level failure such as a bad pull-request selector, no pull request for the branch, a missing repository, or an authentication problem — not a failed-check result. Re-check the selector and \`gh auth status\`.\n\n${formattedWatchOutput.text}`);
183
+ }
184
+ }
185
+ else if (watchExitCode === 8) {
186
+ throw new Error(`GitHub CI watch exited while checks were still pending (exit code 8); refusing to treat this as a terminal result.\n\n${formattedWatchOutput.text}`);
187
+ }
188
+ else if (watchExitCode !== 0) {
189
+ throw new Error(`GitHub CI watch exited unexpectedly${watchExitCode === null ? " without an exit code" : ` with code ${watchExitCode}`}.\n\n${formattedWatchOutput.text}`);
176
190
  }
177
- if (exitCode === 1) {
178
- const cliFailure = detectGhCliFailure(output);
191
+ const finalOutput = createOutputBuffer("[Earlier final checks output omitted]");
192
+ let finalExitCode;
193
+ try {
194
+ ({ exitCode: finalExitCode } = await operations.exec(finalArgs, cwd, {
195
+ onData: (data) => finalOutput.append(data),
196
+ signal,
197
+ env,
198
+ }));
199
+ }
200
+ catch (error) {
201
+ const output = finalOutput.hasOutput() ? `${finalOutput.format().text}\n\n` : "";
202
+ if (error instanceof Error && error.message === "aborted") {
203
+ throw new Error(`${output}GitHub CI final checks query aborted.`);
204
+ }
205
+ const message = error instanceof Error ? error.message : String(error);
206
+ throw new Error(`${output}GitHub CI final checks query could not run: ${message}`);
207
+ }
208
+ const formattedFinalOutput = finalOutput.format();
209
+ if (finalExitCode === 1) {
210
+ const cliFailure = detectGhCliFailure(formattedFinalOutput.text);
179
211
  if (cliFailure !== null) {
180
- throw new Error(`GitHub CI watch could not query checks: the GitHub CLI reported an error (matched "${cliFailure}"). This is a CLI-level failure such as a bad pull-request selector, no pull request for the branch, a missing repository, or an authentication problem — not a failed-check result. Re-check the selector and \`gh auth status\`.\n\n${output}`);
212
+ throw new Error(`GitHub CI final checks query failed: the GitHub CLI reported an error (matched "${cliFailure}"). Re-check the selector and \`gh auth status\`.\n\n${formattedFinalOutput.text}`);
181
213
  }
214
+ }
215
+ else if (finalExitCode === 8) {
216
+ throw new Error(`GitHub CI final checks query found checks still pending (exit code 8) after the watch reported a terminal result.\n\n${formattedFinalOutput.text}`);
217
+ }
218
+ else if (finalExitCode !== 0) {
219
+ throw new Error(`GitHub CI final checks query exited unexpectedly${finalExitCode === null ? " without an exit code" : ` with code ${finalExitCode}`}.\n\n${formattedFinalOutput.text}`);
220
+ }
221
+ if (watchExitCode !== finalExitCode) {
222
+ throw new Error(`GitHub CI status changed between watch completion (exit code ${watchExitCode}) and the final checks query (exit code ${finalExitCode}); refusing to report a contradictory result.\n\n${formattedFinalOutput.text}`);
223
+ }
224
+ if (finalExitCode === 0) {
182
225
  return {
183
- content: [
184
- {
185
- type: "text",
186
- text: `GitHub CI checks did not pass. The GitHub CLI exited with code 1.\n\n${output}`,
187
- },
188
- ],
189
- details: details("failed", exitCode),
226
+ content: [{ type: "text", text: `GitHub CI checks passed.\n\n${formattedFinalOutput.text}` }],
227
+ details: details("passed", formattedFinalOutput.truncated, finalExitCode),
190
228
  };
191
229
  }
192
- if (exitCode === 8) {
193
- throw new Error(`GitHub CI watch exited while checks were still pending (exit code 8); refusing to treat this as a terminal result.\n\n${output}`);
194
- }
195
- throw new Error(`GitHub CI watch exited unexpectedly${exitCode === null ? " without an exit code" : ` with code ${exitCode}`}.\n\n${output}`);
230
+ return {
231
+ content: [
232
+ {
233
+ type: "text",
234
+ text: `GitHub CI checks did not pass. The GitHub CLI exited with code 1.\n\n${formattedFinalOutput.text}`,
235
+ },
236
+ ],
237
+ details: details("failed", formattedFinalOutput.truncated, finalExitCode),
238
+ };
196
239
  },
197
240
  };
198
241
  }
@@ -1 +1 @@
1
- {"version":3,"file":"watch-github-ci.js","sourceRoot":"","sources":["../../../src/core/tools/watch-github-ci.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport type { AgentTool } from \"@dreb/agent-core\";\nimport { type Static, Type } from \"@sinclair/typebox\";\nimport { waitForChildProcess } from \"../../utils/child-process.js\";\nimport { getShellEnv, killProcessTree } from \"../../utils/shell.js\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { renderTerminalOutput } from \"./terminal-render.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\nimport { DEFAULT_MAX_BYTES, truncateTail } from \"./truncate.js\";\n\nconst watchGithubCiSchema = Type.Object({\n\tpr: Type.Optional(\n\t\tType.String({\n\t\t\tdescription:\n\t\t\t\t\"Optional pull request number, URL, or branch. Omit to use the pull request for the current branch.\",\n\t\t}),\n\t),\n});\n\nexport type WatchGithubCiToolInput = Static<typeof watchGithubCiSchema>;\n\nexport interface WatchGithubCiToolDetails {\n\tstatus: \"watching\" | \"passed\" | \"failed\";\n\texitCode?: number;\n\toutputTruncated: boolean;\n}\n\nexport interface GithubCiOperations {\n\texec: (\n\t\targs: readonly string[],\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tsignal?: AbortSignal;\n\t\t\tenv: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<{ exitCode: number | null }>;\n}\n\nexport interface WatchGithubCiToolOptions {\n\toperations?: GithubCiOperations;\n}\n\n/**\n * Substrings (matched case-insensitively) that identify a `gh pr checks` CLI-level\n * failure rather than a real failed-check result. `gh pr checks` exits 1 for both,\n * and `--json` is incompatible with `--watch`, so the captured output is the only\n * way to tell them apart. These signatures are specific enough that they will not\n * appear in a normal check-status table.\n */\nconst GH_CLI_FAILURE_SIGNATURES = [\n\t\"no pull requests found\",\n\t\"could not resolve to a pullrequest\",\n\t\"failed to run git\",\n\t\"not a git repository\",\n\t\"http 401\",\n\t\"bad credentials\",\n\t\"could not parse\",\n\t\"invalid pull request\",\n\t\"authentication required\",\n\t\"could not find repository\",\n];\n\nfunction detectGhCliFailure(output: string): string | null {\n\tconst lower = output.toLowerCase();\n\tfor (const signature of GH_CLI_FAILURE_SIGNATURES) {\n\t\tif (lower.includes(signature)) {\n\t\t\treturn signature;\n\t\t}\n\t}\n\treturn null;\n}\n\nexport function createLocalGithubCiOperations(): GithubCiOperations {\n\treturn {\n\t\texec: (args, cwd, { onData, signal, env }) =>\n\t\t\tnew Promise((resolve, reject) => {\n\t\t\t\tif (!existsSync(cwd)) {\n\t\t\t\t\treject(new Error(`Working directory does not exist: ${cwd}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst child = spawn(\"gh\", [...args], {\n\t\t\t\t\tcwd,\n\t\t\t\t\tdetached: true,\n\t\t\t\t\tenv,\n\t\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\t});\n\t\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\t\tchild.stderr?.on(\"data\", onData);\n\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t\t};\n\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\t\t\twaitForChildProcess(child)\n\t\t\t\t\t.then((exitCode) => {\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\treject(new Error(\"aborted\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresolve({ exitCode });\n\t\t\t\t\t})\n\t\t\t\t\t.catch((error) => {\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\treject(error);\n\t\t\t\t\t});\n\t\t\t}),\n\t};\n}\n\nfunction formatOutput(chunks: readonly Buffer[], omittedEarlierOutput: boolean): { text: string; truncated: boolean } {\n\tconst rendered = renderTerminalOutput(Buffer.concat(chunks).toString(\"utf-8\"));\n\tconst truncation = truncateTail(rendered);\n\tconst prefix = omittedEarlierOutput ? \"[Earlier watch output omitted]\\n\" : \"\";\n\treturn {\n\t\ttext: `${prefix}${truncation.content || \"(no output)\"}`,\n\t\ttruncated: omittedEarlierOutput || truncation.truncated,\n\t};\n}\n\nexport function createWatchGithubCiToolDefinition(\n\tcwd: string,\n\toptions?: WatchGithubCiToolOptions,\n): ToolDefinition<typeof watchGithubCiSchema, WatchGithubCiToolDetails> {\n\tconst operations = options?.operations ?? createLocalGithubCiOperations();\n\n\treturn {\n\t\tname: \"watch_github_ci\",\n\t\tlabel: \"watch GitHub CI\",\n\t\tdescription:\n\t\t\t\"Watch GitHub pull-request checks until they pass or fail. Uses the current branch's pull request by default, or an optional pull request number, URL, or branch. Returns the final GitHub CLI output without requiring user input.\",\n\t\tpromptSnippet: \"Watch GitHub pull-request CI until checks pass or fail\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use `watch_github_ci` to wait for GitHub pull-request checks instead of asking the user, polling with repeated commands, sleeping, or using `wait`\",\n\t\t\t\"`watch_github_ci` blocks until the selected pull request's checks pass or fail; omit `pr` to use the current branch's pull request\",\n\t\t],\n\t\tparameters: watchGithubCiSchema,\n\t\tasync execute(_toolCallId, params, signal, onUpdate) {\n\t\t\tconst selector = params.pr?.trim();\n\t\t\tif (params.pr !== undefined && !selector) {\n\t\t\t\tthrow new Error(\"Pull request selector must not be blank.\");\n\t\t\t}\n\t\t\tif (selector?.startsWith(\"-\")) {\n\t\t\t\tthrow new Error(\"Pull request selector must not begin with '-'.\");\n\t\t\t}\n\n\t\t\tconst args = [\"pr\", \"checks\", ...(selector ? [selector] : []), \"--watch\", \"--fail-fast\"];\n\t\t\tconst chunks: Buffer[] = [];\n\t\t\tlet chunksBytes = 0;\n\t\t\tlet omittedEarlierOutput = false;\n\t\t\tlet outputTruncated = false;\n\t\t\tconst maxBufferedBytes = DEFAULT_MAX_BYTES * 2;\n\n\t\t\tconst details = (status: WatchGithubCiToolDetails[\"status\"], exitCode?: number) => ({\n\t\t\t\tstatus,\n\t\t\t\texitCode,\n\t\t\t\toutputTruncated,\n\t\t\t});\n\t\t\tconst currentOutput = (): string => {\n\t\t\t\tconst formatted = formatOutput(chunks, omittedEarlierOutput);\n\t\t\t\toutputTruncated = formatted.truncated;\n\t\t\t\treturn formatted.text;\n\t\t\t};\n\t\t\tconst onData = (data: Buffer) => {\n\t\t\t\tchunks.push(data);\n\t\t\t\tchunksBytes += data.length;\n\t\t\t\twhile (chunksBytes > maxBufferedBytes) {\n\t\t\t\t\tconst excess = chunksBytes - maxBufferedBytes;\n\t\t\t\t\tconst first = chunks[0];\n\t\t\t\t\tif (first.length <= excess) {\n\t\t\t\t\t\tchunks.shift();\n\t\t\t\t\t\tchunksBytes -= first.length;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tchunks[0] = first.subarray(excess);\n\t\t\t\t\t\tchunksBytes -= excess;\n\t\t\t\t\t}\n\t\t\t\t\tomittedEarlierOutput = true;\n\t\t\t\t}\n\t\t\t\tonUpdate?.({\n\t\t\t\t\tcontent: [{ type: \"text\", text: currentOutput() }],\n\t\t\t\t\tdetails: details(\"watching\"),\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tonUpdate?.({ content: [], details: details(\"watching\") });\n\n\t\t\tlet exitCode: number | null;\n\t\t\ttry {\n\t\t\t\t({ exitCode } = await operations.exec(args, cwd, {\n\t\t\t\t\tonData,\n\t\t\t\t\tsignal,\n\t\t\t\t\tenv: {\n\t\t\t\t\t\t...getShellEnv(),\n\t\t\t\t\t\tGH_PAGER: \"cat\",\n\t\t\t\t\t\tGH_EDITOR: \"cat\",\n\t\t\t\t\t\tNO_COLOR: \"1\",\n\t\t\t\t\t},\n\t\t\t\t}));\n\t\t\t} catch (error) {\n\t\t\t\tconst output = chunks.length > 0 ? `${currentOutput()}\\n\\n` : \"\";\n\t\t\t\tif (error instanceof Error && error.message === \"aborted\") {\n\t\t\t\t\tthrow new Error(`${output}GitHub CI watch aborted.`);\n\t\t\t\t}\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new Error(`${output}GitHub CI watch could not run: ${message}`);\n\t\t\t}\n\n\t\t\tconst output = currentOutput();\n\t\t\tif (exitCode === 0) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `GitHub CI checks passed.\\n\\n${output}` }],\n\t\t\t\t\tdetails: details(\"passed\", exitCode),\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (exitCode === 1) {\n\t\t\t\tconst cliFailure = detectGhCliFailure(output);\n\t\t\t\tif (cliFailure !== null) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`GitHub CI watch could not query checks: the GitHub CLI reported an error (matched \"${cliFailure}\"). This is a CLI-level failure such as a bad pull-request selector, no pull request for the branch, a missing repository, or an authentication problem — not a failed-check result. Re-check the selector and \\`gh auth status\\`.\\n\\n${output}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `GitHub CI checks did not pass. The GitHub CLI exited with code 1.\\n\\n${output}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: details(\"failed\", exitCode),\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (exitCode === 8) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`GitHub CI watch exited while checks were still pending (exit code 8); refusing to treat this as a terminal result.\\n\\n${output}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow new Error(\n\t\t\t\t`GitHub CI watch exited unexpectedly${exitCode === null ? \" without an exit code\" : ` with code ${exitCode}`}.\\n\\n${output}`,\n\t\t\t);\n\t\t},\n\t};\n}\n\nexport function createWatchGithubCiTool(\n\tcwd: string,\n\toptions?: WatchGithubCiToolOptions,\n): AgentTool<typeof watchGithubCiSchema> {\n\treturn wrapToolDefinition(createWatchGithubCiToolDefinition(cwd, options));\n}\n\nexport const watchGithubCiToolDefinition = createWatchGithubCiToolDefinition(process.cwd());\nexport const watchGithubCiTool = createWatchGithubCiTool(process.cwd());\n"]}
1
+ {"version":3,"file":"watch-github-ci.js","sourceRoot":"","sources":["../../../src/core/tools/watch-github-ci.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EAAe,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAEhE,MAAM,mBAAmB,GAAG,IAAI,CAAC,MAAM,CAAC;IACvC,EAAE,EAAE,IAAI,CAAC,QAAQ,CAChB,IAAI,CAAC,MAAM,CAAC;QACX,WAAW,EACV,oGAAoG;KACrG,CAAC,CACF;CACD,CAAC,CAAC;AA0BH;;;;;;GAMG;AACH,MAAM,yBAAyB,GAAG;IACjC,wBAAwB;IACxB,oCAAoC;IACpC,mBAAmB;IACnB,sBAAsB;IACtB,UAAU;IACV,iBAAiB;IACjB,iBAAiB;IACjB,sBAAsB;IACtB,yBAAyB;IACzB,2BAA2B;CAC3B,CAAC;AAEF,SAAS,kBAAkB,CAAC,MAAc,EAAiB;IAC1D,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACnC,KAAK,MAAM,SAAS,IAAI,yBAAyB,EAAE,CAAC;QACnD,IAAI,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAC/B,OAAO,SAAS,CAAC;QAClB,CAAC;IACF,CAAC;IACD,OAAO,IAAI,CAAC;AAAA,CACZ;AAED,MAAM,UAAU,6BAA6B,GAAuB;IACnE,OAAO;QACN,IAAI,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,CAC5C,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;YAChC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtB,MAAM,CAAC,IAAI,KAAK,CAAC,qCAAqC,GAAG,EAAE,CAAC,CAAC,CAAC;gBAC9D,OAAO;YACR,CAAC;YACD,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;gBACrB,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;gBAC7B,OAAO;YACR,CAAC;YAED,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE;gBACpC,GAAG;gBACH,QAAQ,EAAE,IAAI;gBACd,GAAG;gBACH,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;aACjC,CAAC,CAAC;YACH,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACjC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAEjC,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC;gBACrB,IAAI,KAAK,CAAC,GAAG;oBAAE,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAAA,CAC1C,CAAC;YACF,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAE3D,mBAAmB,CAAC,KAAK,CAAC;iBACxB,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC;gBACnB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBAC9C,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;oBACrB,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;oBAC7B,OAAO;gBACR,CAAC;gBACD,OAAO,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;YAAA,CACtB,CAAC;iBACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;gBACjB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBAC9C,MAAM,CAAC,KAAK,CAAC,CAAC;YAAA,CACd,CAAC,CAAC;QAAA,CACJ,CAAC;KACH,CAAC;AAAA,CACF;AAQD,SAAS,kBAAkB,CAAC,aAAqB,EAAgB;IAChE,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,oBAAoB,GAAG,KAAK,CAAC;IACjC,MAAM,gBAAgB,GAAG,iBAAiB,GAAG,CAAC,CAAC;IAE/C,OAAO;QACN,MAAM,CAAC,IAAI,EAAE;YACZ,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClB,WAAW,IAAI,IAAI,CAAC,MAAM,CAAC;YAC3B,OAAO,WAAW,GAAG,gBAAgB,EAAE,CAAC;gBACvC,MAAM,MAAM,GAAG,WAAW,GAAG,gBAAgB,CAAC;gBAC9C,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;gBACxB,IAAI,KAAK,CAAC,MAAM,IAAI,MAAM,EAAE,CAAC;oBAC5B,MAAM,CAAC,KAAK,EAAE,CAAC;oBACf,WAAW,IAAI,KAAK,CAAC,MAAM,CAAC;gBAC7B,CAAC;qBAAM,CAAC;oBACP,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;oBACnC,WAAW,IAAI,MAAM,CAAC;gBACvB,CAAC;gBACD,oBAAoB,GAAG,IAAI,CAAC;YAC7B,CAAC;QAAA,CACD;QACD,MAAM,GAAG;YACR,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;YAC/E,MAAM,UAAU,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,oBAAoB,CAAC,CAAC,CAAC,GAAG,aAAa,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAChE,OAAO;gBACN,IAAI,EAAE,GAAG,MAAM,GAAG,UAAU,CAAC,OAAO,IAAI,aAAa,EAAE;gBACvD,SAAS,EAAE,oBAAoB,IAAI,UAAU,CAAC,SAAS;aACvD,CAAC;QAAA,CACF;QACD,SAAS,GAAG;YACX,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QAAA,CACzB;KACD,CAAC;AAAA,CACF;AAED,MAAM,UAAU,iCAAiC,CAChD,GAAW,EACX,OAAkC,EACqC;IACvE,MAAM,UAAU,GAAG,OAAO,EAAE,UAAU,IAAI,6BAA6B,EAAE,CAAC;IAE1E,OAAO;QACN,IAAI,EAAE,iBAAiB;QACvB,KAAK,EAAE,iBAAiB;QACxB,WAAW,EACV,oOAAoO;QACrO,aAAa,EAAE,wDAAwD;QACvE,gBAAgB,EAAE;YACjB,oJAAoJ;YACpJ,oIAAoI;SACpI;QACD,UAAU,EAAE,mBAAmB;QAC/B,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE;YACpD,MAAM,QAAQ,GAAG,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC;YACnC,IAAI,MAAM,CAAC,EAAE,KAAK,SAAS,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC1C,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;YAC7D,CAAC;YACD,IAAI,QAAQ,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;YACnE,CAAC;YAED,MAAM,SAAS,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;YAC9F,MAAM,SAAS,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACpE,MAAM,GAAG,GAAG;gBACX,GAAG,WAAW,EAAE;gBAChB,QAAQ,EAAE,KAAK;gBACf,SAAS,EAAE,KAAK;gBAChB,QAAQ,EAAE,GAAG;aACb,CAAC;YACF,MAAM,OAAO,GAAG,CAAC,MAA0C,EAAE,eAAwB,EAAE,QAAiB,EAAE,EAAE,CAAC,CAAC;gBAC7G,MAAM;gBACN,QAAQ;gBACR,eAAe;aACf,CAAC,CAAC;YAEH,MAAM,WAAW,GAAG,kBAAkB,CAAC,gCAAgC,CAAC,CAAC;YACzE,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC;gBACrC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBACzB,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC;gBACvC,QAAQ,EAAE,CAAC;oBACV,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC;oBACjD,OAAO,EAAE,OAAO,CAAC,UAAU,EAAE,SAAS,CAAC,SAAS,CAAC;iBACjD,CAAC,CAAC;YAAA,CACH,CAAC;YAEF,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;YAEjE,IAAI,aAA4B,CAAC;YACjC,IAAI,CAAC;gBACJ,CAAC,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE;oBACpE,MAAM,EAAE,WAAW;oBACnB,MAAM;oBACN,GAAG;iBACH,CAAC,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,MAAM,MAAM,GAAG,WAAW,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjF,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;oBAC3D,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,0BAA0B,CAAC,CAAC;gBACtD,CAAC;gBACD,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACvE,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,kCAAkC,OAAO,EAAE,CAAC,CAAC;YACvE,CAAC;YAED,MAAM,oBAAoB,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC;YAClD,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;gBACzB,MAAM,UAAU,GAAG,kBAAkB,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;gBACjE,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;oBACzB,MAAM,IAAI,KAAK,CACd,sFAAsF,UAAU,2OAAyO,oBAAoB,CAAC,IAAI,EAAE,CACpW,CAAC;gBACH,CAAC;YACF,CAAC;iBAAM,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;gBAChC,MAAM,IAAI,KAAK,CACd,yHAAyH,oBAAoB,CAAC,IAAI,EAAE,CACpJ,CAAC;YACH,CAAC;iBAAM,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;gBAChC,MAAM,IAAI,KAAK,CACd,sCAAsC,aAAa,KAAK,IAAI,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,cAAc,aAAa,EAAE,QAAQ,oBAAoB,CAAC,IAAI,EAAE,CACzJ,CAAC;YACH,CAAC;YAED,MAAM,WAAW,GAAG,kBAAkB,CAAC,uCAAuC,CAAC,CAAC;YAChF,IAAI,aAA4B,CAAC;YACjC,IAAI,CAAC;gBACJ,CAAC,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE;oBACpE,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC;oBAC1C,MAAM;oBACN,GAAG;iBACH,CAAC,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,MAAM,MAAM,GAAG,WAAW,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjF,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;oBAC3D,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,uCAAuC,CAAC,CAAC;gBACnE,CAAC;gBACD,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACvE,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,+CAA+C,OAAO,EAAE,CAAC,CAAC;YACpF,CAAC;YAED,MAAM,oBAAoB,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC;YAClD,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;gBACzB,MAAM,UAAU,GAAG,kBAAkB,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;gBACjE,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;oBACzB,MAAM,IAAI,KAAK,CACd,mFAAmF,UAAU,wDAAwD,oBAAoB,CAAC,IAAI,EAAE,CAChL,CAAC;gBACH,CAAC;YACF,CAAC;iBAAM,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;gBAChC,MAAM,IAAI,KAAK,CACd,wHAAwH,oBAAoB,CAAC,IAAI,EAAE,CACnJ,CAAC;YACH,CAAC;iBAAM,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;gBAChC,MAAM,IAAI,KAAK,CACd,mDAAmD,aAAa,KAAK,IAAI,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,cAAc,aAAa,EAAE,QAAQ,oBAAoB,CAAC,IAAI,EAAE,CACtK,CAAC;YACH,CAAC;YAED,IAAI,aAAa,KAAK,aAAa,EAAE,CAAC;gBACrC,MAAM,IAAI,KAAK,CACd,gEAAgE,aAAa,2CAA2C,aAAa,oDAAoD,oBAAoB,CAAC,IAAI,EAAE,CACpN,CAAC;YACH,CAAC;YAED,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;gBACzB,OAAO;oBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,+BAA+B,oBAAoB,CAAC,IAAI,EAAE,EAAE,CAAC;oBAC7F,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,oBAAoB,CAAC,SAAS,EAAE,aAAa,CAAC;iBACzE,CAAC;YACH,CAAC;YACD,OAAO;gBACN,OAAO,EAAE;oBACR;wBACC,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,wEAAwE,oBAAoB,CAAC,IAAI,EAAE;qBACzG;iBACD;gBACD,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,oBAAoB,CAAC,SAAS,EAAE,aAAa,CAAC;aACzE,CAAC;QAAA,CACF;KACD,CAAC;AAAA,CACF;AAED,MAAM,UAAU,uBAAuB,CACtC,GAAW,EACX,OAAkC,EACM;IACxC,OAAO,kBAAkB,CAAC,iCAAiC,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;AAAA,CAC3E;AAED,MAAM,CAAC,MAAM,2BAA2B,GAAG,iCAAiC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;AAC5F,MAAM,CAAC,MAAM,iBAAiB,GAAG,uBAAuB,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport type { AgentTool } from \"@dreb/agent-core\";\nimport { type Static, Type } from \"@sinclair/typebox\";\nimport { waitForChildProcess } from \"../../utils/child-process.js\";\nimport { getShellEnv, killProcessTree } from \"../../utils/shell.js\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { renderTerminalOutput } from \"./terminal-render.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\nimport { DEFAULT_MAX_BYTES, truncateTail } from \"./truncate.js\";\n\nconst watchGithubCiSchema = Type.Object({\n\tpr: Type.Optional(\n\t\tType.String({\n\t\t\tdescription:\n\t\t\t\t\"Optional pull request number, URL, or branch. Omit to use the pull request for the current branch.\",\n\t\t}),\n\t),\n});\n\nexport type WatchGithubCiToolInput = Static<typeof watchGithubCiSchema>;\n\nexport interface WatchGithubCiToolDetails {\n\tstatus: \"watching\" | \"passed\" | \"failed\";\n\texitCode?: number;\n\toutputTruncated: boolean;\n}\n\nexport interface GithubCiOperations {\n\texec: (\n\t\targs: readonly string[],\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tsignal?: AbortSignal;\n\t\t\tenv: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<{ exitCode: number | null }>;\n}\n\nexport interface WatchGithubCiToolOptions {\n\toperations?: GithubCiOperations;\n}\n\n/**\n * Substrings (matched case-insensitively) that identify a `gh pr checks` CLI-level\n * failure rather than a real failed-check result. `gh pr checks` exits 1 for both,\n * and `--json` is incompatible with `--watch`, so the captured output is the only\n * way to tell them apart. These signatures are specific enough that they will not\n * appear in a normal check-status table.\n */\nconst GH_CLI_FAILURE_SIGNATURES = [\n\t\"no pull requests found\",\n\t\"could not resolve to a pullrequest\",\n\t\"failed to run git\",\n\t\"not a git repository\",\n\t\"http 401\",\n\t\"bad credentials\",\n\t\"could not parse\",\n\t\"invalid pull request\",\n\t\"authentication required\",\n\t\"could not find repository\",\n];\n\nfunction detectGhCliFailure(output: string): string | null {\n\tconst lower = output.toLowerCase();\n\tfor (const signature of GH_CLI_FAILURE_SIGNATURES) {\n\t\tif (lower.includes(signature)) {\n\t\t\treturn signature;\n\t\t}\n\t}\n\treturn null;\n}\n\nexport function createLocalGithubCiOperations(): GithubCiOperations {\n\treturn {\n\t\texec: (args, cwd, { onData, signal, env }) =>\n\t\t\tnew Promise((resolve, reject) => {\n\t\t\t\tif (!existsSync(cwd)) {\n\t\t\t\t\treject(new Error(`Working directory does not exist: ${cwd}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst child = spawn(\"gh\", [...args], {\n\t\t\t\t\tcwd,\n\t\t\t\t\tdetached: true,\n\t\t\t\t\tenv,\n\t\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\t});\n\t\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\t\tchild.stderr?.on(\"data\", onData);\n\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t\t};\n\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\t\t\twaitForChildProcess(child)\n\t\t\t\t\t.then((exitCode) => {\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\treject(new Error(\"aborted\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresolve({ exitCode });\n\t\t\t\t\t})\n\t\t\t\t\t.catch((error) => {\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\treject(error);\n\t\t\t\t\t});\n\t\t\t}),\n\t};\n}\n\ninterface OutputBuffer {\n\tappend(data: Buffer): void;\n\tformat(): { text: string; truncated: boolean };\n\thasOutput(): boolean;\n}\n\nfunction createOutputBuffer(omittedPrefix: string): OutputBuffer {\n\tconst chunks: Buffer[] = [];\n\tlet chunksBytes = 0;\n\tlet omittedEarlierOutput = false;\n\tconst maxBufferedBytes = DEFAULT_MAX_BYTES * 2;\n\n\treturn {\n\t\tappend(data) {\n\t\t\tchunks.push(data);\n\t\t\tchunksBytes += data.length;\n\t\t\twhile (chunksBytes > maxBufferedBytes) {\n\t\t\t\tconst excess = chunksBytes - maxBufferedBytes;\n\t\t\t\tconst first = chunks[0];\n\t\t\t\tif (first.length <= excess) {\n\t\t\t\t\tchunks.shift();\n\t\t\t\t\tchunksBytes -= first.length;\n\t\t\t\t} else {\n\t\t\t\t\tchunks[0] = first.subarray(excess);\n\t\t\t\t\tchunksBytes -= excess;\n\t\t\t\t}\n\t\t\t\tomittedEarlierOutput = true;\n\t\t\t}\n\t\t},\n\t\tformat() {\n\t\t\tconst rendered = renderTerminalOutput(Buffer.concat(chunks).toString(\"utf-8\"));\n\t\t\tconst truncation = truncateTail(rendered);\n\t\t\tconst prefix = omittedEarlierOutput ? `${omittedPrefix}\\n` : \"\";\n\t\t\treturn {\n\t\t\t\ttext: `${prefix}${truncation.content || \"(no output)\"}`,\n\t\t\t\ttruncated: omittedEarlierOutput || truncation.truncated,\n\t\t\t};\n\t\t},\n\t\thasOutput() {\n\t\t\treturn chunks.length > 0;\n\t\t},\n\t};\n}\n\nexport function createWatchGithubCiToolDefinition(\n\tcwd: string,\n\toptions?: WatchGithubCiToolOptions,\n): ToolDefinition<typeof watchGithubCiSchema, WatchGithubCiToolDetails> {\n\tconst operations = options?.operations ?? createLocalGithubCiOperations();\n\n\treturn {\n\t\tname: \"watch_github_ci\",\n\t\tlabel: \"watch GitHub CI\",\n\t\tdescription:\n\t\t\t\"Watch GitHub pull-request checks until they pass or fail. Uses the current branch's pull request by default, or an optional pull request number, URL, or branch. Returns the final GitHub CLI output without requiring user input.\",\n\t\tpromptSnippet: \"Watch GitHub pull-request CI until checks pass or fail\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use `watch_github_ci` to wait for GitHub pull-request checks instead of asking the user, polling with repeated commands, sleeping, or using `wait`\",\n\t\t\t\"`watch_github_ci` blocks until the selected pull request's checks pass or fail; omit `pr` to use the current branch's pull request\",\n\t\t],\n\t\tparameters: watchGithubCiSchema,\n\t\tasync execute(_toolCallId, params, signal, onUpdate) {\n\t\t\tconst selector = params.pr?.trim();\n\t\t\tif (params.pr !== undefined && !selector) {\n\t\t\t\tthrow new Error(\"Pull request selector must not be blank.\");\n\t\t\t}\n\t\t\tif (selector?.startsWith(\"-\")) {\n\t\t\t\tthrow new Error(\"Pull request selector must not begin with '-'.\");\n\t\t\t}\n\n\t\t\tconst watchArgs = [\"pr\", \"checks\", ...(selector ? [selector] : []), \"--watch\", \"--fail-fast\"];\n\t\t\tconst finalArgs = [\"pr\", \"checks\", ...(selector ? [selector] : [])];\n\t\t\tconst env = {\n\t\t\t\t...getShellEnv(),\n\t\t\t\tGH_PAGER: \"cat\",\n\t\t\t\tGH_EDITOR: \"cat\",\n\t\t\t\tNO_COLOR: \"1\",\n\t\t\t};\n\t\t\tconst details = (status: WatchGithubCiToolDetails[\"status\"], outputTruncated: boolean, exitCode?: number) => ({\n\t\t\t\tstatus,\n\t\t\t\texitCode,\n\t\t\t\toutputTruncated,\n\t\t\t});\n\n\t\t\tconst watchOutput = createOutputBuffer(\"[Earlier watch output omitted]\");\n\t\t\tconst onWatchData = (data: Buffer) => {\n\t\t\t\twatchOutput.append(data);\n\t\t\t\tconst formatted = watchOutput.format();\n\t\t\t\tonUpdate?.({\n\t\t\t\t\tcontent: [{ type: \"text\", text: formatted.text }],\n\t\t\t\t\tdetails: details(\"watching\", formatted.truncated),\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tonUpdate?.({ content: [], details: details(\"watching\", false) });\n\n\t\t\tlet watchExitCode: number | null;\n\t\t\ttry {\n\t\t\t\t({ exitCode: watchExitCode } = await operations.exec(watchArgs, cwd, {\n\t\t\t\t\tonData: onWatchData,\n\t\t\t\t\tsignal,\n\t\t\t\t\tenv,\n\t\t\t\t}));\n\t\t\t} catch (error) {\n\t\t\t\tconst output = watchOutput.hasOutput() ? `${watchOutput.format().text}\\n\\n` : \"\";\n\t\t\t\tif (error instanceof Error && error.message === \"aborted\") {\n\t\t\t\t\tthrow new Error(`${output}GitHub CI watch aborted.`);\n\t\t\t\t}\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new Error(`${output}GitHub CI watch could not run: ${message}`);\n\t\t\t}\n\n\t\t\tconst formattedWatchOutput = watchOutput.format();\n\t\t\tif (watchExitCode === 1) {\n\t\t\t\tconst cliFailure = detectGhCliFailure(formattedWatchOutput.text);\n\t\t\t\tif (cliFailure !== null) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`GitHub CI watch could not query checks: the GitHub CLI reported an error (matched \"${cliFailure}\"). This is a CLI-level failure such as a bad pull-request selector, no pull request for the branch, a missing repository, or an authentication problem — not a failed-check result. Re-check the selector and \\`gh auth status\\`.\\n\\n${formattedWatchOutput.text}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else if (watchExitCode === 8) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`GitHub CI watch exited while checks were still pending (exit code 8); refusing to treat this as a terminal result.\\n\\n${formattedWatchOutput.text}`,\n\t\t\t\t);\n\t\t\t} else if (watchExitCode !== 0) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`GitHub CI watch exited unexpectedly${watchExitCode === null ? \" without an exit code\" : ` with code ${watchExitCode}`}.\\n\\n${formattedWatchOutput.text}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst finalOutput = createOutputBuffer(\"[Earlier final checks output omitted]\");\n\t\t\tlet finalExitCode: number | null;\n\t\t\ttry {\n\t\t\t\t({ exitCode: finalExitCode } = await operations.exec(finalArgs, cwd, {\n\t\t\t\t\tonData: (data) => finalOutput.append(data),\n\t\t\t\t\tsignal,\n\t\t\t\t\tenv,\n\t\t\t\t}));\n\t\t\t} catch (error) {\n\t\t\t\tconst output = finalOutput.hasOutput() ? `${finalOutput.format().text}\\n\\n` : \"\";\n\t\t\t\tif (error instanceof Error && error.message === \"aborted\") {\n\t\t\t\t\tthrow new Error(`${output}GitHub CI final checks query aborted.`);\n\t\t\t\t}\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new Error(`${output}GitHub CI final checks query could not run: ${message}`);\n\t\t\t}\n\n\t\t\tconst formattedFinalOutput = finalOutput.format();\n\t\t\tif (finalExitCode === 1) {\n\t\t\t\tconst cliFailure = detectGhCliFailure(formattedFinalOutput.text);\n\t\t\t\tif (cliFailure !== null) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`GitHub CI final checks query failed: the GitHub CLI reported an error (matched \"${cliFailure}\"). Re-check the selector and \\`gh auth status\\`.\\n\\n${formattedFinalOutput.text}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else if (finalExitCode === 8) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`GitHub CI final checks query found checks still pending (exit code 8) after the watch reported a terminal result.\\n\\n${formattedFinalOutput.text}`,\n\t\t\t\t);\n\t\t\t} else if (finalExitCode !== 0) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`GitHub CI final checks query exited unexpectedly${finalExitCode === null ? \" without an exit code\" : ` with code ${finalExitCode}`}.\\n\\n${formattedFinalOutput.text}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (watchExitCode !== finalExitCode) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`GitHub CI status changed between watch completion (exit code ${watchExitCode}) and the final checks query (exit code ${finalExitCode}); refusing to report a contradictory result.\\n\\n${formattedFinalOutput.text}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (finalExitCode === 0) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `GitHub CI checks passed.\\n\\n${formattedFinalOutput.text}` }],\n\t\t\t\t\tdetails: details(\"passed\", formattedFinalOutput.truncated, finalExitCode),\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `GitHub CI checks did not pass. The GitHub CLI exited with code 1.\\n\\n${formattedFinalOutput.text}`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdetails: details(\"failed\", formattedFinalOutput.truncated, finalExitCode),\n\t\t\t};\n\t\t},\n\t};\n}\n\nexport function createWatchGithubCiTool(\n\tcwd: string,\n\toptions?: WatchGithubCiToolOptions,\n): AgentTool<typeof watchGithubCiSchema> {\n\treturn wrapToolDefinition(createWatchGithubCiToolDefinition(cwd, options));\n}\n\nexport const watchGithubCiToolDefinition = createWatchGithubCiToolDefinition(process.cwd());\nexport const watchGithubCiTool = createWatchGithubCiTool(process.cwd());\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dreb/coding-agent",
3
- "version": "2.61.1",
3
+ "version": "2.61.2",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "drebConfig": {