diffing 0.10.0 → 0.10.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/dist/{cli-agent-CLrK54k2.mjs → cli-agent-CV0k1pXp.mjs} +10 -8
- package/dist/cli-gh-C2LAp12S.mjs +313 -0
- package/dist/cli.mjs +3 -3
- package/dist/client/assets/{angular-html-DdAR2u-k.js → angular-html-CV0Ak818.js} +1 -1
- package/dist/client/assets/{angular-ts-Dz_vWKSu.js → angular-ts-2e8zQ7to.js} +1 -1
- package/dist/client/assets/{apl-BJ5QXrIk.js → apl-ByVy2dfo.js} +1 -1
- package/dist/client/assets/{arc-D9erSW6x.js → arc--R8kldOB.js} +1 -1
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-CCQWZLXR.js → architectureDiagram-3BPJPVTR-BWbm1lrV.js} +1 -1
- package/dist/client/assets/{astro-BQAej5a5.js → astro-CE7ySGnq.js} +1 -1
- package/dist/client/assets/{blade-DkAmuwDx.js → blade-PJJaH6RK.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-vwjxNybI.js → blockDiagram-GPEHLZMM-BdfBhnvZ.js} +1 -1
- package/dist/client/assets/{c-DG5p-ChJ.js → c-BhDzEkUq.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-DJ_hVlh4.js → c4Diagram-AAUBKEIU-Bu_tfvPY.js} +1 -1
- package/dist/client/assets/channel-DSEnsd3l.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-CiLowxCo.js → chunk-2J33WTMH-CTGsTtve.js} +1 -1
- package/dist/client/assets/{chunk-3OPIFGDE-H3jjMR5Y.js → chunk-3OPIFGDE-BODO_5hx.js} +1 -1
- package/dist/client/assets/{chunk-4BX2VUAB-Dk0dk4n5.js → chunk-4BX2VUAB-BTsyFV0Y.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-nbLiUMJS.js → chunk-55IACEB6-DnrCm6LC.js} +1 -1
- package/dist/client/assets/{chunk-5ZQYHXKU-DZ8RgHg8.js → chunk-5ZQYHXKU-DBjF0sdg.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-DDe5dqJV.js → chunk-727SXJPM-Do27Z5ji.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-DmpNclOr.js → chunk-AQP2D5EJ-CTnpneGA.js} +1 -1
- package/dist/client/assets/{chunk-BSJP7CBP-BKQKvtIj.js → chunk-BSJP7CBP-Kr0_rIcG.js} +1 -1
- package/dist/client/assets/{chunk-CSCIHK7Q-D27t4cyv.js → chunk-CSCIHK7Q-vYCYu98G.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-Bu3LA663.js → chunk-FMBD7UC4-D325zkwE.js} +1 -1
- package/dist/client/assets/{chunk-KSCS5N6A-Ed5HNXRW.js → chunk-KSCS5N6A-Byf7HmWv.js} +1 -1
- package/dist/client/assets/{chunk-L5ZTLDWV-DLjJZgf8.js → chunk-L5ZTLDWV-D6bS5hm3.js} +1 -1
- package/dist/client/assets/{chunk-LZXEDZCA-B-cs89SM.js → chunk-LZXEDZCA-BMGYcU-n.js} +2 -2
- package/dist/client/assets/{chunk-ND2GUHAM-D_kPSuUA.js → chunk-ND2GUHAM-xfJDzv5I.js} +1 -1
- package/dist/client/assets/{chunk-NZK2D7GU-D1u3pjq-.js → chunk-NZK2D7GU-DY1HNoUO.js} +1 -1
- package/dist/client/assets/{chunk-O5CBEL6O-Mt0cnPSf.js → chunk-O5CBEL6O-BFgywBQV.js} +1 -1
- package/dist/client/assets/chunk-QZHKN3VN-wL51hu-L.js +1 -0
- package/dist/client/assets/chunk-WU5MYG2G-DcSuLObv.js +1 -0
- package/dist/client/assets/{chunk-XPW4576I-Bt8a8x28.js → chunk-XPW4576I-CCOlY0K5.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-Cd9P7jo-.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-_8XVmWNY.js +1 -0
- package/dist/client/assets/{cobol-Daidj_5Y.js → cobol-D5uvQocP.js} +1 -1
- package/dist/client/assets/{coffee-DUMdB2Cr.js → coffee-DoE1_DMC.js} +1 -1
- package/dist/client/assets/{cose-bilkent-S5V4N54A-DVUDLXie.js → cose-bilkent-S5V4N54A-BffMlb0t.js} +1 -1
- package/dist/client/assets/{cpp-C2FeX1Mc.js → cpp-CxMs3g8q.js} +1 -1
- package/dist/client/assets/{crystal-D4yb9blJ.js → crystal-Ck_Sab8H.js} +1 -1
- package/dist/client/assets/{css-B5cr0U9F.js → css-Bx3zqeyw.js} +1 -1
- package/dist/client/assets/{dagre-BM42HDAG-DdZWb-Ee.js → dagre-BM42HDAG-DuK7JkP6.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-C9DOZt92.js → diagram-2AECGRRQ-DW9W2wY6.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-Bbc07UKr.js → diagram-5GNKFQAL-CfmdY-KT.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-C-lUzY3m.js → diagram-KO2AKTUF-C3W0AVns.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-D-OjEFhp.js → diagram-LMA3HP47-Jxoj1EBH.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-BjtWGvrf.js → diagram-OG6HWLK6-DKZXYFSu.js} +1 -1
- package/dist/client/assets/{dist-BXZygPdX.js → dist-Cxgi_w93.js} +1 -1
- package/dist/client/assets/{edge-RCQWcWNp.js → edge-D7XVJcl7.js} +1 -1
- package/dist/client/assets/{elixir-DwKyVg2X.js → elixir-DLQjwJ9Q.js} +1 -1
- package/dist/client/assets/{elm-DjR33IVs.js → elm-CP5Ox5XO.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-C5T4ywLG.js → erDiagram-TEJ5UH35-BGd46oGi.js} +1 -1
- package/dist/client/assets/{erb-BnhUH1Hk.js → erb-C97aW-va.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-BJmjm7Kx.js → flowDiagram-I6XJVG4X-D6MFCwKy.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-DREPnzu5.js → ganttDiagram-6RSMTGT7-i1RH9KFv.js} +1 -1
- package/dist/client/assets/{git-rebase-DzXoSDXA.js → git-rebase-B4iN-h71.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-DIR4G_-_.js → gitGraphDiagram-PVQCEYII-DiLnrGe6.js} +1 -1
- package/dist/client/assets/{glimmer-js-HKnZpCn_.js → glimmer-js-DVkEnHRb.js} +1 -1
- package/dist/client/assets/{glimmer-ts-DedV7rWs.js → glimmer-ts-CyUzWW2D.js} +1 -1
- package/dist/client/assets/{glsl-Bz-0Alp2.js → glsl-5XFOCOCu.js} +1 -1
- package/dist/client/assets/{graphql-DSKkDYCD.js → graphql-IoOZHuWD.js} +1 -1
- package/dist/client/assets/{hack-CnaHZm8k.js → hack-BUQ8LqBu.js} +1 -1
- package/dist/client/assets/{haml-huGFYKlj.js → haml-BIbv0YDp.js} +1 -1
- package/dist/client/assets/{handlebars-CKmgzfWY.js → handlebars-9QihiA8n.js} +1 -1
- package/dist/client/assets/{html-B9Ih_dUU.js → html-5bjcBKb2.js} +1 -1
- package/dist/client/assets/{html-derivative-YabD-M5d.js → html-derivative-DFAt3hvS.js} +1 -1
- package/dist/client/assets/{http-Bdu12JYX.js → http-4_xHs8PR.js} +1 -1
- package/dist/client/assets/{hurl-twZzDTNs.js → hurl-B-wi-Gx2.js} +1 -1
- package/dist/client/assets/{index-BktdZRWB.js → index-CHvT3DR9.js} +10 -10
- package/dist/client/assets/{infoDiagram-5YYISTIA-D2ty2R-i.js → infoDiagram-5YYISTIA-Dy1M2f6k.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-Ccnc9xlE.js → ishikawaDiagram-YF4QCWOH-J9qG2PlR.js} +1 -1
- package/dist/client/assets/{java-_5trO-p9.js → java-D9isH882.js} +1 -1
- package/dist/client/assets/{javascript-BOQn0ikE.js → javascript-Dj8e4yT5.js} +1 -1
- package/dist/client/assets/{jinja-BgY-0IBz.js → jinja-Bkare_Hv.js} +1 -1
- package/dist/client/assets/{jison-BLNTmT1_.js → jison-DDIUNnOW.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-W7eWXlw0.js → journeyDiagram-JHISSGLW-Do4kGeyR.js} +1 -1
- package/dist/client/assets/{json-BLbH8rZf.js → json-Bi84FPdJ.js} +1 -1
- package/dist/client/assets/{jsx-CxteptsJ.js → jsx-DI-NKxp6.js} +1 -1
- package/dist/client/assets/{julia-B__Ncp_z.js → julia-Yhlqb4JO.js} +1 -1
- package/dist/client/assets/{just-DBsHUGW1.js → just-B8KISqsZ.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-Z_AFL-rd.js → kanban-definition-UN3LZRKU-BSeQxfa9.js} +1 -1
- package/dist/client/assets/{latex-DFF_0wxo.js → latex-CkYf4HIK.js} +1 -1
- package/dist/client/assets/{line-aAv8TyOs.js → line-C2Za_tgK.js} +1 -1
- package/dist/client/assets/{linear-BOvEZKH8.js → linear-CRm3pgdR.js} +1 -1
- package/dist/client/assets/{liquid-kDWCO6d7.js → liquid-y_Utf1BC.js} +1 -1
- package/dist/client/assets/{lua-CYTFayq-.js → lua-C4gbVDKd.js} +1 -1
- package/dist/client/assets/{marko-Dpmz3Pdx.js → marko-BlcQZIyX.js} +1 -1
- package/dist/client/assets/{mdc-BsxHyM1i.js → mdc-C6KkSPM_.js} +1 -1
- package/dist/client/assets/{mermaid-parser.core-D8z_CWL1.js → mermaid-parser.core-B9mHNH7g.js} +1 -1
- package/dist/client/assets/{mermaid.core-DNKchnly.js → mermaid.core-pkJSRcFi.js} +3 -3
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-xQKMV4Kw.js → mindmap-definition-RKZ34NQL-BAW_jZIg.js} +1 -1
- package/dist/client/assets/{nginx-CcdTDme-.js → nginx-BGbv5z-H.js} +1 -1
- package/dist/client/assets/{nim-B5wWDskL.js → nim-BtqaozVV.js} +1 -1
- package/dist/client/assets/{perl-Ce2_iKLz.js → perl-BaPVFzDG.js} +1 -1
- package/dist/client/assets/{php-DuLCFERd.js → php-CUSmmFXP.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-CBSCJnUr.js → pieDiagram-4H26LBE5-DHTW5bo3.js} +1 -1
- package/dist/client/assets/{pug-BfQJoQj1.js → pug-ComryLhI.js} +1 -1
- package/dist/client/assets/{qml-DYeovlVl.js → qml-D4-pUDzN.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-uEcgb0Rm.js → quadrantDiagram-W4KKPZXB-oE0LSIIu.js} +1 -1
- package/dist/client/assets/{r-DgHSP56L.js → r-IEiS2KmQ.js} +1 -1
- package/dist/client/assets/{razor-B00x7W-i.js → razor-A3NOQ-6o.js} +1 -1
- package/dist/client/assets/{regexp-CmWVupmd.js → regexp-Dnh3EraB.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-Q4yY_ALe.js → requirementDiagram-4Y6WPE33-CAnOHDxz.js} +1 -1
- package/dist/client/assets/{review-export-pcqDKNqx.js → review-export-D-wScR31.js} +1 -1
- package/dist/client/assets/{rst-B3VARbTX.js → rst-DDcT8Cwj.js} +1 -1
- package/dist/client/assets/{ruby-CaxKSSbT.js → ruby-BqnC7im3.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-B-GLzFGa.js → sankeyDiagram-5OEKKPKP-DARazeui.js} +1 -1
- package/dist/client/assets/{sas-Ue0rHUIk.js → sas-BsVPIslL.js} +1 -1
- package/dist/client/assets/{scss-BJJ7_L6c.js → scss-Cs-F21hy.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-DW0em0D_.js → sequenceDiagram-3UESZ5HK-BYAKokia.js} +1 -1
- package/dist/client/assets/{shellscript-C6LkZs1u.js → shellscript-CuqRpwp7.js} +1 -1
- package/dist/client/assets/{shellsession-CkZu1e84.js → shellsession-BT4CTJst.js} +1 -1
- package/dist/client/assets/{soy-CDaZV57J.js → soy-Njc_erP7.js} +1 -1
- package/dist/client/assets/{sql-CLfMGH4x.js → sql-C0M8bIzv.js} +1 -1
- package/dist/client/assets/{src-C27zxuNO.js → src-B8u-CQt1.js} +1 -1
- package/dist/client/assets/{stata-B0kNMHc9.js → stata-DQWLgfGE.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-CrO_D3m4.js → stateDiagram-AJRCARHV-CL6IO6Yx.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-CXkQIsOM.js +1 -0
- package/dist/client/assets/{surrealql-D9os_yZO.js → surrealql-CxnsjSMN.js} +1 -1
- package/dist/client/assets/{svelte-2SxVToeO.js → svelte-YiRJWdT-.js} +1 -1
- package/dist/client/assets/{templ-DzmZB67T.js → templ-DVHepm0I.js} +1 -1
- package/dist/client/assets/{tex-BMPk3nHk.js → tex-CbaeWbjN.js} +1 -1
- package/dist/client/assets/{timeline-definition-PNZ67QCA-C9FBevHv.js → timeline-definition-PNZ67QCA-BAKLMRXW.js} +1 -1
- package/dist/client/assets/{ts-tags-CG14Bplc.js → ts-tags-KadJLbnQ.js} +1 -1
- package/dist/client/assets/{tsx-D6NK461A.js → tsx-DgmkmSe3.js} +1 -1
- package/dist/client/assets/{twig-Agh0j5sD.js → twig-BG7aoIMU.js} +1 -1
- package/dist/client/assets/{typescript-_AkeziZ2.js → typescript-C_w_yccd.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-2H9HfhhR.js → vennDiagram-CIIHVFJN-CCRx_JXh.js} +1 -1
- package/dist/client/assets/{vue-C1z3QGG9.js → vue-DXnUyZR0.js} +1 -1
- package/dist/client/assets/{vue-html-C1RMzLZk.js → vue-html-CetUfade.js} +1 -1
- package/dist/client/assets/{vue-vine-oOixA6ge.js → vue-vine-CSW5RjCH.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-BJxrQhTf.js → wardleyDiagram-YWT4CUSO-Buoffz1N.js} +1 -1
- package/dist/client/assets/{xml-okuDZ7vq.js → xml-CJgpX9jH.js} +1 -1
- package/dist/client/assets/{xsl-S_n3XrKb.js → xsl-BZk-xhGC.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-BGdee7KG.js → xychartDiagram-2RQKCTM6-CEKRZKfv.js} +1 -1
- package/dist/client/assets/{yaml-BoX-kqX1.js → yaml-DVxl0VLy.js} +1 -1
- package/dist/client/index.html +1 -1
- package/dist/{completions-ZSKYvW06.mjs → completions-Csvfqctx.mjs} +16 -1
- package/dist/{doctor-CmP0u7-d.mjs → doctor-DhuZFVwO.mjs} +1 -1
- package/dist/{github-oCZx5aim.mjs → github-CzxbZnhh.mjs} +152 -28
- package/dist/github-DL7-BqhD.mjs +2 -0
- package/dist/{mcp-CqxXILYL.mjs → mcp-BBDdXGOZ.mjs} +212 -28
- package/dist/{server-CczuXSWo.mjs → server-D-gJ7owz.mjs} +947 -54
- package/package.json +1 -1
- package/dist/cli-gh-8YC1NzyM.mjs +0 -155
- package/dist/client/assets/channel-DmZgR6r0.js +0 -1
- package/dist/client/assets/chunk-QZHKN3VN-BrYnBs7h.js +0 -1
- package/dist/client/assets/chunk-WU5MYG2G-CdBcsQs_.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-CCpp3t5M.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-B1aV1sYb.js +0 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-C9KDGD7R.js +0 -1
- package/dist/github-BjZZcSKV.mjs +0 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as buildGitDiffArgs, o as parseDiffOptions, t as startServer } from "./server-
|
|
1
|
+
import { i as buildGitDiffArgs, o as parseDiffOptions, t as startServer } from "./server-D-gJ7owz.mjs";
|
|
2
2
|
import { t as formatComments } from "./comment-format-B5AcGcR-.mjs";
|
|
3
3
|
import { n as formatPlanReview } from "./plan-format-BQyx--mp.mjs";
|
|
4
4
|
import { a as removeServerLock, i as readServerLock, n as diffScopeKey, o as removeServerLockIfOwned, r as isLockAlive, s as writeServerLock, t as acquireServerStartupLease } from "./server-lock-uqSdDYeR.mjs";
|
|
@@ -345,7 +345,7 @@ function createMcpServer(options) {
|
|
|
345
345
|
const ownerId = options.ownerId ?? randomUUID();
|
|
346
346
|
const defaultClientDir = existsSync(resolve(moduleDirectory, "client")) ? resolve(moduleDirectory, "client") : resolve(repoRoot, "dist/client");
|
|
347
347
|
const clientDir = options.clientDir ?? defaultClientDir;
|
|
348
|
-
const instructions = `diffing is bound to ${repoRoot} for this connection. First call review_session_status. If no web session is running, call start_review_session; it is safe to retry and never replaces a user session. For code review,
|
|
348
|
+
const instructions = `diffing is bound to ${repoRoot} for this connection. First call review_session_status. If no web session is running, call start_review_session; it is safe to retry and never replaces a user session. For code review, prefer diff_summary then paged diff_files/diff_hunks/diff_slice over get_diff; create_comment as needed, then await_review for the human handoff. For a GitHub PR session, call gh_overview and bounded diff tools; use gh_list_threads/reviews for discussion, and mutate GitHub only with explicit user authorization. For plan review, call submit_plan then await_plan_review. A changes-requested verdict means revise and resubmit the same planId; rejected means stop; approved means proceed. Wait tools return released or timeout with a mode; timeout is not failure and the same wait tool may be called again. MCP connects only to the loopback diffing server; explicitly authorized GitHub tools may make the server call GitHub.`;
|
|
349
349
|
const server = new McpServer({
|
|
350
350
|
name: "diffing",
|
|
351
351
|
version: MCP_VERSION
|
|
@@ -360,11 +360,10 @@ function createMcpServer(options) {
|
|
|
360
360
|
if (lock.owner === "mcp" && (lock.pid !== process.pid || lock.ownerId !== ownerId)) throw new Error(`A different diffing MCP connection (${lock.pid}/${lock.ownerId ?? "legacy"}) owns this repository session. Its web server lifecycle is tied to that MCP connection; stop it or wait for it to exit, then retry.`);
|
|
361
361
|
if (!isLoopbackHost(lock.host)) throw new Error(`The active diffing session is bound to non-loopback host ${JSON.stringify(lock.host)}. MCP refuses LAN/remote review URLs; end it and call start_review_session for a loopback-only session.`);
|
|
362
362
|
}
|
|
363
|
-
function
|
|
363
|
+
function requireAnySession() {
|
|
364
364
|
const lock = liveLock();
|
|
365
|
-
if (!lock) throw new Error(`No diffing
|
|
365
|
+
if (!lock) throw new Error(`No diffing review session is running for ${repoRoot}. Start one with start_review_session, \`diffing --web\`, or \`diffing "gh pr <ref>"\`, then retry.`);
|
|
366
366
|
ensureReusableLock(lock);
|
|
367
|
-
if ((lock.mode ?? "web") === "gh-pr") throw new Error("The active diffing session is a GitHub PR review, not a local review.");
|
|
368
367
|
const url = lockUrl(lock);
|
|
369
368
|
if (!url) throw new Error("The active diffing session does not expose a reachable loopback API.");
|
|
370
369
|
return {
|
|
@@ -373,6 +372,16 @@ function createMcpServer(options) {
|
|
|
373
372
|
identity: `${lock.pid}:${lock.startedAt}:${lock.port}:${lock.ownerId ?? ""}`
|
|
374
373
|
};
|
|
375
374
|
}
|
|
375
|
+
function requireWebSession() {
|
|
376
|
+
const session = requireAnySession();
|
|
377
|
+
if ((session.lock.mode ?? "web") === "gh-pr") throw new Error("The active diffing session is a GitHub PR review, not a local review. Use gh_* tools and bounded diff_* inspect tools, or end the PR session for local review/plan tools.");
|
|
378
|
+
return session;
|
|
379
|
+
}
|
|
380
|
+
function requireGhPrSession() {
|
|
381
|
+
const session = requireAnySession();
|
|
382
|
+
if ((session.lock.mode ?? "web") !== "gh-pr") throw new Error("This tool requires an active GitHub PR session (`diffing \"gh pr <ref>\"` or --gh-pr).");
|
|
383
|
+
return session;
|
|
384
|
+
}
|
|
376
385
|
function requestSessionJson(session, path, init = {}) {
|
|
377
386
|
const headers = new Headers(init.headers);
|
|
378
387
|
if (session.lock.mode === "tui") {
|
|
@@ -387,10 +396,9 @@ function createMcpServer(options) {
|
|
|
387
396
|
function requestBaseJson(path, init) {
|
|
388
397
|
return requestSessionJson(requireWebSession(), path, init);
|
|
389
398
|
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
return session;
|
|
399
|
+
/** Bounded inspect works for web, tui, and gh-pr sessions. */
|
|
400
|
+
function requireInspectSession() {
|
|
401
|
+
return requireAnySession();
|
|
394
402
|
}
|
|
395
403
|
async function seedReviewCursor(session, signal) {
|
|
396
404
|
if (reviewCursor?.identity === session.identity) return reviewCursor.round;
|
|
@@ -431,7 +439,7 @@ function createMcpServer(options) {
|
|
|
431
439
|
url,
|
|
432
440
|
managedBy: lock.owner === "mcp" ? "mcp" : "user",
|
|
433
441
|
diffArgs: lock.diffArgs ?? [],
|
|
434
|
-
nextAction: inaccessible ? "This session is not loopback-only, so MCP will not connect to it. End it manually and call start_review_session." : mode === "tui" ? "
|
|
442
|
+
nextAction: inaccessible ? "This session is not loopback-only, so MCP will not connect to it. End it manually and call start_review_session." : mode === "tui" ? "Use bounded diff_summary/diff_files/diff_hunks/diff_slice/diff_search, then local review tools." : mode === "gh-pr" ? "Use gh_overview, then diff_summary→diff_files→diff_hunks/diff_slice/diff_search. For discussion use gh_list_threads (prefer unresolvedOnly). Do not fetch the full patch via get_diff." : "Prefer diff_summary→diff_files→diff_slice over get_diff. Use plan-review tools when gating implementation."
|
|
435
443
|
};
|
|
436
444
|
}
|
|
437
445
|
server.registerTool("review_session_status", {
|
|
@@ -602,18 +610,18 @@ function createMcpServer(options) {
|
|
|
602
610
|
return textResult(diff.patch || "(The active diff is empty.)", structured);
|
|
603
611
|
});
|
|
604
612
|
server.registerTool("diff_summary", {
|
|
605
|
-
title: "Summarize the
|
|
606
|
-
description: "Return bounded totals and change-kind counts
|
|
613
|
+
title: "Summarize the active diff (bounded)",
|
|
614
|
+
description: "Return bounded totals and change-kind counts without transferring the patch. Works for web, TUI, and GitHub PR sessions. Prefer this over get_diff.",
|
|
607
615
|
inputSchema: {},
|
|
608
616
|
outputSchema: { result: z.unknown() },
|
|
609
617
|
annotations: READ_ONLY
|
|
610
618
|
}, async () => {
|
|
611
|
-
const result = await requestSessionJson(
|
|
619
|
+
const result = await requestSessionJson(requireInspectSession(), "/api/diff/summary");
|
|
612
620
|
return textResult(JSON.stringify(result), { result });
|
|
613
621
|
});
|
|
614
622
|
server.registerTool("diff_files", {
|
|
615
|
-
title: "Page changed files
|
|
616
|
-
description: "Return a bounded page of changed-file metadata with an opaque numeric continuation cursor.",
|
|
623
|
+
title: "Page changed files (bounded)",
|
|
624
|
+
description: "Return a bounded page of changed-file metadata with an opaque numeric continuation cursor. Works for web, TUI, and GitHub PR sessions.",
|
|
617
625
|
inputSchema: {
|
|
618
626
|
cursor: z.number().int().nonnegative().optional(),
|
|
619
627
|
limit: z.number().int().positive().max(1e3).optional()
|
|
@@ -621,12 +629,12 @@ function createMcpServer(options) {
|
|
|
621
629
|
outputSchema: { result: z.unknown() },
|
|
622
630
|
annotations: READ_ONLY
|
|
623
631
|
}, async ({ cursor = 0, limit = 100 }) => {
|
|
624
|
-
const result = await requestSessionJson(
|
|
632
|
+
const result = await requestSessionJson(requireInspectSession(), `/api/diff/files?cursor=${cursor}&limit=${limit}`);
|
|
625
633
|
return textResult(JSON.stringify(result), { result });
|
|
626
634
|
});
|
|
627
635
|
server.registerTool("diff_hunks", {
|
|
628
|
-
title: "Page hunk metadata
|
|
629
|
-
description: "Return bounded hunk metadata for one file index. Pass generation from diff_summary to reject stale navigation.",
|
|
636
|
+
title: "Page hunk metadata (bounded)",
|
|
637
|
+
description: "Return bounded hunk metadata for one file index. Pass generation from diff_summary to reject stale navigation. Works for web, TUI, and GitHub PR sessions.",
|
|
630
638
|
inputSchema: {
|
|
631
639
|
file: z.number().int().nonnegative(),
|
|
632
640
|
generation: z.number().int().nonnegative().optional(),
|
|
@@ -636,7 +644,7 @@ function createMcpServer(options) {
|
|
|
636
644
|
outputSchema: { result: z.unknown() },
|
|
637
645
|
annotations: READ_ONLY
|
|
638
646
|
}, async ({ file, generation, cursor = 0, limit = 100 }) => {
|
|
639
|
-
const session =
|
|
647
|
+
const session = requireInspectSession();
|
|
640
648
|
const query = new URLSearchParams({
|
|
641
649
|
file: String(file),
|
|
642
650
|
cursor: String(cursor),
|
|
@@ -647,8 +655,8 @@ function createMcpServer(options) {
|
|
|
647
655
|
return textResult(JSON.stringify(result), { result });
|
|
648
656
|
});
|
|
649
657
|
server.registerTool("diff_slice", {
|
|
650
|
-
title: "Read a bounded
|
|
651
|
-
description: "Read exact logical rows for one file with strict line and byte budgets; use nextRow to continue.",
|
|
658
|
+
title: "Read a bounded diff slice",
|
|
659
|
+
description: "Read exact logical rows for one file with strict line and byte budgets; use nextRow to continue. Works for web, TUI, and GitHub PR sessions. Prefer this over get_diff.",
|
|
652
660
|
inputSchema: {
|
|
653
661
|
file: z.number().int().nonnegative(),
|
|
654
662
|
start: z.number().int().nonnegative().optional(),
|
|
@@ -659,7 +667,7 @@ function createMcpServer(options) {
|
|
|
659
667
|
outputSchema: { result: z.unknown() },
|
|
660
668
|
annotations: READ_ONLY
|
|
661
669
|
}, async ({ file, start = 0, generation, maxLines = 120, maxBytes = 256 * 1024 }) => {
|
|
662
|
-
const session =
|
|
670
|
+
const session = requireInspectSession();
|
|
663
671
|
const query = new URLSearchParams({
|
|
664
672
|
file: String(file),
|
|
665
673
|
start: String(start),
|
|
@@ -671,8 +679,8 @@ function createMcpServer(options) {
|
|
|
671
679
|
return textResult(JSON.stringify(result), { result });
|
|
672
680
|
});
|
|
673
681
|
server.registerTool("diff_search", {
|
|
674
|
-
title: "Search the
|
|
675
|
-
description: "Search changed paths and content with bounded hits/bytes and generation-safe continuation coordinates.",
|
|
682
|
+
title: "Search the active diff (bounded)",
|
|
683
|
+
description: "Search changed paths and content with bounded hits/bytes and generation-safe continuation coordinates. Works for web, TUI, and GitHub PR sessions.",
|
|
676
684
|
inputSchema: {
|
|
677
685
|
query: z.string().min(1),
|
|
678
686
|
generation: z.number().int().nonnegative().optional(),
|
|
@@ -684,7 +692,7 @@ function createMcpServer(options) {
|
|
|
684
692
|
outputSchema: { result: z.unknown() },
|
|
685
693
|
annotations: READ_ONLY
|
|
686
694
|
}, async ({ query, generation, file = 0, row = 0, limit = 100, maxBytes = 256 * 1024 }) => {
|
|
687
|
-
const session =
|
|
695
|
+
const session = requireInspectSession();
|
|
688
696
|
const params = new URLSearchParams({
|
|
689
697
|
q: query,
|
|
690
698
|
file: String(file),
|
|
@@ -696,6 +704,177 @@ function createMcpServer(options) {
|
|
|
696
704
|
const result = await requestSessionJson(session, `/api/diff/search?${params}`);
|
|
697
705
|
return textResult(JSON.stringify(result), { result });
|
|
698
706
|
});
|
|
707
|
+
server.registerTool("gh_overview", {
|
|
708
|
+
title: "GitHub PR overview (slim)",
|
|
709
|
+
description: "Return compact PR identity, SHAs, size stats, and thread/review/draft counts without the patch or full conversation bodies. Requires an active gh-pr session.",
|
|
710
|
+
inputSchema: {},
|
|
711
|
+
outputSchema: { result: z.unknown() },
|
|
712
|
+
annotations: READ_ONLY
|
|
713
|
+
}, async () => {
|
|
714
|
+
const result = await requestSessionJson(requireGhPrSession(), "/api/gh/overview");
|
|
715
|
+
return textResult(JSON.stringify(result), { result });
|
|
716
|
+
});
|
|
717
|
+
server.registerTool("gh_list_threads", {
|
|
718
|
+
title: "List published PR review threads",
|
|
719
|
+
description: "Page published GitHub review threads with filters. Prefer unresolvedOnly=true. Bodies are truncated by default; set fullBody for complete text. format=xml for agent XML.",
|
|
720
|
+
inputSchema: {
|
|
721
|
+
unresolvedOnly: z.boolean().optional(),
|
|
722
|
+
path: z.string().optional(),
|
|
723
|
+
author: z.string().optional(),
|
|
724
|
+
cursor: z.number().int().nonnegative().optional(),
|
|
725
|
+
limit: z.number().int().positive().max(200).optional(),
|
|
726
|
+
bodyMaxChars: z.number().int().positive().max(5e4).optional(),
|
|
727
|
+
fullBody: z.boolean().optional(),
|
|
728
|
+
format: z.enum(["json", "xml"]).optional()
|
|
729
|
+
},
|
|
730
|
+
outputSchema: { result: z.unknown() },
|
|
731
|
+
annotations: READ_ONLY
|
|
732
|
+
}, async ({ unresolvedOnly, path, author, cursor = 0, limit = 50, bodyMaxChars = 500, fullBody, format = "json" }) => {
|
|
733
|
+
const session = requireGhPrSession();
|
|
734
|
+
const params = new URLSearchParams({
|
|
735
|
+
cursor: String(cursor),
|
|
736
|
+
limit: String(limit),
|
|
737
|
+
bodyMaxChars: String(bodyMaxChars),
|
|
738
|
+
format
|
|
739
|
+
});
|
|
740
|
+
if (unresolvedOnly) params.set("unresolvedOnly", "true");
|
|
741
|
+
if (path) params.set("path", path);
|
|
742
|
+
if (author) params.set("author", author);
|
|
743
|
+
if (fullBody) params.set("fullBody", "true");
|
|
744
|
+
if (format === "xml") {
|
|
745
|
+
const res = await fetch(`${session.url}/api/gh/threads?${params}`);
|
|
746
|
+
const text = await res.text();
|
|
747
|
+
if (!res.ok) throw new Error(text || res.statusText);
|
|
748
|
+
return textResult(text, { result: {
|
|
749
|
+
format: "xml",
|
|
750
|
+
xml: text
|
|
751
|
+
} });
|
|
752
|
+
}
|
|
753
|
+
const result = await requestSessionJson(session, `/api/gh/threads?${params}`);
|
|
754
|
+
return textResult(JSON.stringify(result), { result });
|
|
755
|
+
});
|
|
756
|
+
server.registerTool("gh_list_reviews", {
|
|
757
|
+
title: "List published PR review events",
|
|
758
|
+
description: "Page submitted GitHub review verdicts and overall comments. Bodies truncated by default.",
|
|
759
|
+
inputSchema: {
|
|
760
|
+
cursor: z.number().int().nonnegative().optional(),
|
|
761
|
+
limit: z.number().int().positive().max(100).optional(),
|
|
762
|
+
bodyMaxChars: z.number().int().positive().max(5e4).optional(),
|
|
763
|
+
fullBody: z.boolean().optional(),
|
|
764
|
+
state: z.string().optional(),
|
|
765
|
+
format: z.enum(["json", "xml"]).optional()
|
|
766
|
+
},
|
|
767
|
+
outputSchema: { result: z.unknown() },
|
|
768
|
+
annotations: READ_ONLY
|
|
769
|
+
}, async ({ cursor = 0, limit = 50, bodyMaxChars = 500, fullBody, state, format = "json" }) => {
|
|
770
|
+
const session = requireGhPrSession();
|
|
771
|
+
const params = new URLSearchParams({
|
|
772
|
+
cursor: String(cursor),
|
|
773
|
+
limit: String(limit),
|
|
774
|
+
bodyMaxChars: String(bodyMaxChars),
|
|
775
|
+
format
|
|
776
|
+
});
|
|
777
|
+
if (fullBody) params.set("fullBody", "true");
|
|
778
|
+
if (state) params.set("state", state);
|
|
779
|
+
if (format === "xml") {
|
|
780
|
+
const res = await fetch(`${session.url}/api/gh/reviews?${params}`);
|
|
781
|
+
const text = await res.text();
|
|
782
|
+
if (!res.ok) throw new Error(text || res.statusText);
|
|
783
|
+
return textResult(text, { result: {
|
|
784
|
+
format: "xml",
|
|
785
|
+
xml: text
|
|
786
|
+
} });
|
|
787
|
+
}
|
|
788
|
+
const result = await requestSessionJson(session, `/api/gh/reviews?${params}`);
|
|
789
|
+
return textResult(JSON.stringify(result), { result });
|
|
790
|
+
});
|
|
791
|
+
server.registerTool("gh_list_draft_comments", {
|
|
792
|
+
title: "List local PR draft comments",
|
|
793
|
+
description: "Return in-progress local draft comments for the active PR session (not published on GitHub).",
|
|
794
|
+
inputSchema: {},
|
|
795
|
+
outputSchema: { comments: z.array(commentSchema) },
|
|
796
|
+
annotations: READ_ONLY
|
|
797
|
+
}, async () => {
|
|
798
|
+
const comments = await requestSessionJson(requireGhPrSession(), "/api/gh/pr-session/comments");
|
|
799
|
+
return textResult(formatComments(comments), { comments });
|
|
800
|
+
});
|
|
801
|
+
server.registerTool("gh_create_draft_comment", {
|
|
802
|
+
title: "Create a local PR draft comment",
|
|
803
|
+
description: "Create a local draft inline comment on the active PR session. Does not publish to GitHub. Use gh_submit_review only when the user explicitly authorized publishing.",
|
|
804
|
+
inputSchema: {
|
|
805
|
+
filePath: z.string().min(1),
|
|
806
|
+
side: z.enum(["deletions", "additions"]),
|
|
807
|
+
lineNumber: z.number().int().nonnegative(),
|
|
808
|
+
startLineNumber: z.number().int().positive().optional(),
|
|
809
|
+
lineContent: z.string().optional(),
|
|
810
|
+
body: z.string().min(1),
|
|
811
|
+
severity: z.enum([
|
|
812
|
+
"blocking",
|
|
813
|
+
"nit",
|
|
814
|
+
"question",
|
|
815
|
+
"praise",
|
|
816
|
+
"none"
|
|
817
|
+
]).optional()
|
|
818
|
+
},
|
|
819
|
+
outputSchema: { comment: commentSchema },
|
|
820
|
+
annotations: MUTATING
|
|
821
|
+
}, async ({ filePath, side, lineNumber, startLineNumber, lineContent, body, severity }) => {
|
|
822
|
+
const comment = await requestSessionJson(requireGhPrSession(), "/api/gh/pr-session/comments", {
|
|
823
|
+
method: "POST",
|
|
824
|
+
headers: { "Content-Type": "application/json" },
|
|
825
|
+
body: JSON.stringify({
|
|
826
|
+
filePath,
|
|
827
|
+
side,
|
|
828
|
+
lineNumber,
|
|
829
|
+
startLineNumber,
|
|
830
|
+
lineContent: lineContent ?? "",
|
|
831
|
+
body,
|
|
832
|
+
severity: severity === "none" ? void 0 : severity
|
|
833
|
+
})
|
|
834
|
+
});
|
|
835
|
+
return textResult(`Created PR draft comment ${comment.id} on ${comment.filePath}:${comment.lineNumber}.`, { comment });
|
|
836
|
+
});
|
|
837
|
+
server.registerTool("gh_refresh", {
|
|
838
|
+
title: "Refresh GitHub PR session",
|
|
839
|
+
description: "Re-fetch PR metadata, patch, and published conversations into the local session (force-push / new review sync).",
|
|
840
|
+
inputSchema: {},
|
|
841
|
+
outputSchema: { result: z.unknown() },
|
|
842
|
+
annotations: MUTATING
|
|
843
|
+
}, async () => {
|
|
844
|
+
const result = await requestSessionJson(requireGhPrSession(), "/api/gh/pr/refresh", { method: "POST" });
|
|
845
|
+
return textResult(JSON.stringify(result), { result });
|
|
846
|
+
});
|
|
847
|
+
server.registerTool("gh_submit_review", {
|
|
848
|
+
title: "Submit PR review to GitHub",
|
|
849
|
+
description: "Publish local draft comments and a decision to GitHub. REQUIRES explicit user authorization — this mutates the remote pull request. Prefer dryRun first.",
|
|
850
|
+
inputSchema: {
|
|
851
|
+
decision: z.enum([
|
|
852
|
+
"approve",
|
|
853
|
+
"comment",
|
|
854
|
+
"request-changes",
|
|
855
|
+
"draft"
|
|
856
|
+
]),
|
|
857
|
+
body: z.string().optional(),
|
|
858
|
+
dryRun: z.boolean().optional()
|
|
859
|
+
},
|
|
860
|
+
outputSchema: { result: z.unknown() },
|
|
861
|
+
annotations: {
|
|
862
|
+
...MUTATING,
|
|
863
|
+
openWorldHint: true,
|
|
864
|
+
destructiveHint: false
|
|
865
|
+
}
|
|
866
|
+
}, async ({ decision, body, dryRun }) => {
|
|
867
|
+
const result = await requestSessionJson(requireGhPrSession(), "/api/gh/submit", {
|
|
868
|
+
method: "POST",
|
|
869
|
+
headers: { "Content-Type": "application/json" },
|
|
870
|
+
body: JSON.stringify({
|
|
871
|
+
decision,
|
|
872
|
+
body: body ?? "",
|
|
873
|
+
dryRun: dryRun === true
|
|
874
|
+
})
|
|
875
|
+
});
|
|
876
|
+
return textResult(JSON.stringify(result), { result });
|
|
877
|
+
});
|
|
699
878
|
server.registerTool("create_comment", {
|
|
700
879
|
title: "Create an inline review comment",
|
|
701
880
|
description: "Create a local inline comment on an exact line (or inclusive range) from get_diff. side is additions for +/context in the new file and deletions for a removed line. Optional severity triages the finding for the human and is included in the agent handoff XML.",
|
|
@@ -1294,7 +1473,7 @@ This MCP connection is immutably bound to \`${repoRoot}\`.
|
|
|
1294
1473
|
|
|
1295
1474
|
## Code review
|
|
1296
1475
|
1. Call \`review_session_status\`; call \`start_review_session\` if needed.
|
|
1297
|
-
2.
|
|
1476
|
+
2. Prefer \`diff_summary\` → paged \`diff_files\` → \`diff_hunks\` / bounded \`diff_slice\`; use \`get_diff\` only as an escape hatch.
|
|
1298
1477
|
3. Use \`create_comment\` for actionable inline findings.
|
|
1299
1478
|
4. Use \`await_review\` for a human handoff; a timeout is safe to retry.
|
|
1300
1479
|
5. In \`comment-only\` mode, reply without editing files.
|
|
@@ -1305,7 +1484,12 @@ This MCP connection is immutably bound to \`${repoRoot}\`.
|
|
|
1305
1484
|
3. On \`changes-requested\`, revise and resubmit with the same \`planId\`.
|
|
1306
1485
|
4. On \`approved\`, proceed; on \`rejected\`, stop.
|
|
1307
1486
|
|
|
1308
|
-
|
|
1487
|
+
## GitHub PR
|
|
1488
|
+
1. In \`gh-pr\` mode call \`gh_overview\`, then the bounded diff tools.
|
|
1489
|
+
2. Fetch published discussion with \`gh_list_threads\` (prefer unresolved) and \`gh_list_reviews\`.
|
|
1490
|
+
3. Local drafts do not publish. Call \`gh_submit_review\` or mutate published threads only with explicit user authorization.
|
|
1491
|
+
|
|
1492
|
+
MCP connects only to the loopback diffing server and never terminates a user-owned session. Explicitly authorized GitHub operations may make that server call GitHub.`
|
|
1309
1493
|
}] }));
|
|
1310
1494
|
server.registerPrompt("review_local_changes", {
|
|
1311
1495
|
title: "Review local changes with diffing",
|
|
@@ -1315,7 +1499,7 @@ All HTTP activity is loopback-only. MCP never terminates a user-owned session.`
|
|
|
1315
1499
|
role: "user",
|
|
1316
1500
|
content: {
|
|
1317
1501
|
type: "text",
|
|
1318
|
-
text: `Use diffing to review the local changes in ${repoRoot}. Check review_session_status, start_review_session if needed, inspect
|
|
1502
|
+
text: `Use diffing to review the local changes in ${repoRoot}. Check review_session_status, start_review_session if needed, inspect with bounded diff_summary/diff_files/diff_hunks/diff_slice calls, and create only actionable inline comments. Review every changed file${focus ? ` with special attention to ${focus}` : ""}.`
|
|
1319
1503
|
}
|
|
1320
1504
|
}] }));
|
|
1321
1505
|
server.registerPrompt("submit_plan_for_review", {
|