diffing 0.17.0 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{cli-agent-qNwkSjxK.mjs → cli-agent-Cf6SAnH4.mjs} +744 -15
- package/dist/{cli-gh-BvoDabKK.mjs → cli-gh-2NEumKQB.mjs} +1 -1
- package/dist/cli.mjs +5 -4
- package/dist/client/assets/{angular-html-ByeJB0rh.js → angular-html-BV3gPi7L.js} +1 -1
- package/dist/client/assets/{angular-ts-CiwZGajG.js → angular-ts-DuuSfKJK.js} +1 -1
- package/dist/client/assets/{apl-C8k5a5fk.js → apl-BMc69egk.js} +1 -1
- package/dist/client/assets/{arc-B8VMoqVr.js → arc-CEC1cz1S.js} +1 -1
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-C-ng2xNL.js → architectureDiagram-3BPJPVTR-BmJ5OHgd.js} +1 -1
- package/dist/client/assets/{astro-BE-h-qpp.js → astro-Bg_CYwmB.js} +1 -1
- package/dist/client/assets/{blade-D-0BV1wW.js → blade-Mca0XoRC.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-DyAQuONU.js → blockDiagram-GPEHLZMM--XrThRLW.js} +1 -1
- package/dist/client/assets/{c-Dg_Gx29H.js → c-B2Uqi6oI.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-k5uKTHvm.js → c4Diagram-AAUBKEIU-W8w5oiRi.js} +1 -1
- package/dist/client/assets/channel-C9URWRe4.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-Dod_VwYj.js → chunk-2J33WTMH-Bpr3MqKf.js} +1 -1
- package/dist/client/assets/{chunk-3OPIFGDE-B8HMjry-.js → chunk-3OPIFGDE-DdMV_3DM.js} +1 -1
- package/dist/client/assets/{chunk-4BX2VUAB-TvkJVIZw.js → chunk-4BX2VUAB-BkfeLLsz.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-BsXuKAKc.js → chunk-55IACEB6-pCwXbxR0.js} +1 -1
- package/dist/client/assets/{chunk-5ZQYHXKU-BI1cj2cZ.js → chunk-5ZQYHXKU-BGFzCgvs.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-yWQ27Wk0.js → chunk-727SXJPM-DU7oVWfJ.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-B2BBCtTr.js → chunk-AQP2D5EJ-DaVYG1qm.js} +1 -1
- package/dist/client/assets/{chunk-BSJP7CBP-CXXvPXhK.js → chunk-BSJP7CBP-DAvnzgjY.js} +1 -1
- package/dist/client/assets/{chunk-CSCIHK7Q-jYiloqyi.js → chunk-CSCIHK7Q-D6ZDvMsi.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-DZzqIT32.js → chunk-FMBD7UC4-BFDCYCqF.js} +1 -1
- package/dist/client/assets/{chunk-KSCS5N6A-krdCf8iG.js → chunk-KSCS5N6A-BmD6XY52.js} +1 -1
- package/dist/client/assets/{chunk-L5ZTLDWV-0uuTmeZV.js → chunk-L5ZTLDWV-Dl9iUIBf.js} +1 -1
- package/dist/client/assets/{chunk-LZXEDZCA-BBfUgD06.js → chunk-LZXEDZCA-rOOJDxdB.js} +2 -2
- package/dist/client/assets/{chunk-ND2GUHAM-jkir4ZKE.js → chunk-ND2GUHAM-DBDu-JeD.js} +1 -1
- package/dist/client/assets/{chunk-NZK2D7GU-DMWZNibJ.js → chunk-NZK2D7GU-CRyk4F3R.js} +1 -1
- package/dist/client/assets/{chunk-O5CBEL6O-B1e1HGaX.js → chunk-O5CBEL6O-DcKB07iP.js} +1 -1
- package/dist/client/assets/chunk-QZHKN3VN-BBNO2-yv.js +1 -0
- package/dist/client/assets/chunk-WU5MYG2G-HP2Om5f9.js +1 -0
- package/dist/client/assets/{chunk-XPW4576I-AvbCAUav.js → chunk-XPW4576I-WuzWMSrp.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-BW_ZPHe7.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-DOd628kk.js +1 -0
- package/dist/client/assets/{cobol-DQnGB_GV.js → cobol-oQ1i-YtO.js} +1 -1
- package/dist/client/assets/{coffee-CDV5a89x.js → coffee-s9XlmHbB.js} +1 -1
- package/dist/client/assets/{cose-bilkent-S5V4N54A-t-mDNRF2.js → cose-bilkent-S5V4N54A-CymUm7fn.js} +1 -1
- package/dist/client/assets/{cpp-8G6b-siI.js → cpp-D60LxTox.js} +1 -1
- package/dist/client/assets/{crystal-CGYCC6FM.js → crystal-CHrCczDb.js} +1 -1
- package/dist/client/assets/{css-nez4R8_Z.js → css-1PQO32Hw.js} +1 -1
- package/dist/client/assets/{dagre-BM42HDAG--azesYIg.js → dagre-BM42HDAG-DOHZc0tO.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-4WJ7nKhA.js → diagram-2AECGRRQ-D8O2cleS.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-C7ZGhLXn.js → diagram-5GNKFQAL-CO-Ej4UD.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-BobK_rbl.js → diagram-KO2AKTUF-DCUr4wzS.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-BOc-OkIS.js → diagram-LMA3HP47-D9HnA0Qg.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-BEtLgm86.js → diagram-OG6HWLK6-BxAitO2n.js} +1 -1
- package/dist/client/assets/{dist-DPuBwToc.js → dist-N-ROBnkL.js} +1 -1
- package/dist/client/assets/{edge-Z5RMbJQv.js → edge-Ck54Fn7y.js} +1 -1
- package/dist/client/assets/{edit-CFxbgVPV.js → edit-B8RwtrDs.js} +1 -1
- package/dist/client/assets/{elixir-d3C79FQc.js → elixir-xXxdfsfU.js} +1 -1
- package/dist/client/assets/{elm-CDAf6Uyn.js → elm-g0vLRWbF.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-D-pR2GY9.js → erDiagram-TEJ5UH35-1ZMg7g98.js} +1 -1
- package/dist/client/assets/{erb-CTJk9FKH.js → erb-CGFnxOST.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-BwMCy2QV.js → flowDiagram-I6XJVG4X-D5u9lhJ-.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-BI1WLJDi.js → ganttDiagram-6RSMTGT7-BbVKEzs8.js} +1 -1
- package/dist/client/assets/{git-rebase-Dr0-MVoW.js → git-rebase-B3s6bE5_.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-CUfW0k1f.js → gitGraphDiagram-PVQCEYII-sAottiiz.js} +1 -1
- package/dist/client/assets/{glimmer-js-CXhLhyW-.js → glimmer-js-C2Xff18_.js} +1 -1
- package/dist/client/assets/{glimmer-ts-BFAFT-VD.js → glimmer-ts-CRBS8ftd.js} +1 -1
- package/dist/client/assets/{glsl-D7yanhgY.js → glsl-aOY_t6dG.js} +1 -1
- package/dist/client/assets/{graphql-CpoDxrok.js → graphql-Cucpdpc6.js} +1 -1
- package/dist/client/assets/{hack-BL5fmC4q.js → hack-Bw0KkVza.js} +1 -1
- package/dist/client/assets/{haml-ClAE6RVM.js → haml-DnyaPoa2.js} +1 -1
- package/dist/client/assets/{handlebars-nHw91uOv.js → handlebars-AedEof-m.js} +1 -1
- package/dist/client/assets/{html-BIiOKqgG.js → html-Bu5h_Kgf.js} +1 -1
- package/dist/client/assets/{html-derivative-D1nPnuOK.js → html-derivative-CNiVLld1.js} +1 -1
- package/dist/client/assets/{http-B_QcRZjt.js → http-B9-oOYPw.js} +1 -1
- package/dist/client/assets/{hurl-CZE0DsD3.js → hurl-Bo6NUnnd.js} +1 -1
- package/dist/client/assets/{index-Erqhm7rW.js → index-BkwV-g6J.js} +91 -91
- package/dist/client/assets/index-C73yr1tm.css +1 -0
- package/dist/client/assets/{infoDiagram-5YYISTIA-w2M_OHua.js → infoDiagram-5YYISTIA-CfVELF4R.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-CW_l9PGx.js → ishikawaDiagram-YF4QCWOH-DztjIGfb.js} +1 -1
- package/dist/client/assets/{java-CXTqX09w.js → java-JJ3dl_jz.js} +1 -1
- package/dist/client/assets/{javascript-9z9ABBep.js → javascript-QgUuQNTw.js} +1 -1
- package/dist/client/assets/{jinja-Cluf_5Bk.js → jinja-GbeEm2-u.js} +1 -1
- package/dist/client/assets/{jison-CqCEUtc4.js → jison-BXZbHsO3.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-D-YwusBa.js → journeyDiagram-JHISSGLW-Lg8CkxeI.js} +1 -1
- package/dist/client/assets/{json-BMq_bPP8.js → json-D02YvQSa.js} +1 -1
- package/dist/client/assets/{jsx-Djij59b9.js → jsx-eZde6NZS.js} +1 -1
- package/dist/client/assets/{julia-DybzCMnh.js → julia-CfcuUD-A.js} +1 -1
- package/dist/client/assets/{just-4ChcAr9-.js → just-hQr8WcQp.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-Brvoukmm.js → kanban-definition-UN3LZRKU-BWIeZIf6.js} +1 -1
- package/dist/client/assets/{latex-CS2TtFXG.js → latex-BxffZwv_.js} +1 -1
- package/dist/client/assets/{line-CqxM-stA.js → line-Cy1AFxf0.js} +1 -1
- package/dist/client/assets/{linear-C7T82059.js → linear-Kk5IbGHr.js} +1 -1
- package/dist/client/assets/{liquid-84AtYenm.js → liquid-BvKnpUyR.js} +1 -1
- package/dist/client/assets/{lua-DJzFx3Cf.js → lua-Bcds2vY9.js} +1 -1
- package/dist/client/assets/{marko-BLw9BV9E.js → marko-CZJQLjYc.js} +1 -1
- package/dist/client/assets/{mdc-BjZejN3b.js → mdc-BRigtixg.js} +1 -1
- package/dist/client/assets/{mermaid-parser.core-BdiEBAsd.js → mermaid-parser.core-Dh2uTVxt.js} +1 -1
- package/dist/client/assets/{mermaid.core-BsnKhnrM.js → mermaid.core-CXIGVQ74.js} +3 -3
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-CBaIFnbc.js → mindmap-definition-RKZ34NQL-DQNQJuAB.js} +1 -1
- package/dist/client/assets/{nginx-DuamCwvX.js → nginx-BI3-LI9U.js} +1 -1
- package/dist/client/assets/{nim-Bt8c9-ge.js → nim-PEd8ZOME.js} +1 -1
- package/dist/client/assets/{perl-D52AfmwC.js → perl-BPTGdP4p.js} +1 -1
- package/dist/client/assets/{php-BBMlJg0_.js → php-C8BKL0yL.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-BlmPajcA.js → pieDiagram-4H26LBE5-Dz7gE0t5.js} +1 -1
- package/dist/client/assets/{pug-DFHmDqEE.js → pug-H5z9rtbz.js} +1 -1
- package/dist/client/assets/{qml-C0333o-g.js → qml-EzSpo2aM.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-Bqlm_zZk.js → quadrantDiagram-W4KKPZXB-pTnmYdEJ.js} +1 -1
- package/dist/client/assets/{r-DZFmvIgR.js → r-VMeUwMIt.js} +1 -1
- package/dist/client/assets/{razor-BIGLkWzR.js → razor-Ne05zcaj.js} +1 -1
- package/dist/client/assets/{regexp-BW6jpgf9.js → regexp-i5_jUZAj.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-B1PrtUeD.js → requirementDiagram-4Y6WPE33-GVw3NOxE.js} +1 -1
- package/dist/client/assets/{review-export-BlgD3bdw.js → review-export-B4TOUDUE.js} +1 -1
- package/dist/client/assets/{rst-Cj51ZJaa.js → rst-BZWuei_6.js} +1 -1
- package/dist/client/assets/{ruby-lMhGjwpf.js → ruby-CApICFTD.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-D2HtUNVF.js → sankeyDiagram-5OEKKPKP-CwWzwmqj.js} +1 -1
- package/dist/client/assets/{sas-BWSQku7l.js → sas-BzEPX6GL.js} +1 -1
- package/dist/client/assets/{scss-CdRPuhLN.js → scss-B6Ld2NRm.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-D9SQy0XI.js → sequenceDiagram-3UESZ5HK-Bz_Q76Kt.js} +1 -1
- package/dist/client/assets/{shellscript-DOfOBXcj.js → shellscript-KmoqGVVu.js} +1 -1
- package/dist/client/assets/{shellsession-7XAOCVni.js → shellsession-CsSh_KTo.js} +1 -1
- package/dist/client/assets/{soy-DDnzVRIw.js → soy-CLgOu1If.js} +1 -1
- package/dist/client/assets/{sql-Ba34agKe.js → sql-BdCh56kU.js} +1 -1
- package/dist/client/assets/{src-BO-qT_v_.js → src-D7QQkGEc.js} +1 -1
- package/dist/client/assets/{stata-BQlYGHQU.js → stata-C3fo8EYS.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-7IEYjFRo.js → stateDiagram-AJRCARHV-D0pZtzLu.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-P0vTqsyH.js +1 -0
- package/dist/client/assets/{surrealql-BET1l7SW.js → surrealql-qzihsJw_.js} +1 -1
- package/dist/client/assets/{svelte-Bd7ZOeQI.js → svelte-B4tbn_KI.js} +1 -1
- package/dist/client/assets/{templ-BYvRQdOw.js → templ-Ddev3BvY.js} +1 -1
- package/dist/client/assets/{tex-CT8DpKxX.js → tex-DJLtgNQ6.js} +1 -1
- package/dist/client/assets/{timeline-definition-PNZ67QCA-CurQYWmi.js → timeline-definition-PNZ67QCA-CWTWgYi0.js} +1 -1
- package/dist/client/assets/{ts-tags-D4iPPwau.js → ts-tags-qqxigRtr.js} +1 -1
- package/dist/client/assets/{tsx-Dgk_Aw-B.js → tsx-Pkf9BaPv.js} +1 -1
- package/dist/client/assets/{twig-abRNWeh3.js → twig-BiScb10p.js} +1 -1
- package/dist/client/assets/{typescript-BgR1JqdC.js → typescript-Bhy3UXig.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-DbrRBL5S.js → vennDiagram-CIIHVFJN-DwB89v9I.js} +1 -1
- package/dist/client/assets/{vue-DSkhKq4Q.js → vue-CANMWBRv.js} +1 -1
- package/dist/client/assets/{vue-html-J0jWoD9X.js → vue-html-DtS6f62r.js} +1 -1
- package/dist/client/assets/{vue-vine-BgX5MC8-.js → vue-vine-BpQ9kwSB.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-DIFXQsoP.js → wardleyDiagram-YWT4CUSO-DNwwPk4s.js} +1 -1
- package/dist/client/assets/{xml-Ca53xGLB.js → xml-CD5eIXsm.js} +1 -1
- package/dist/client/assets/{xsl-CNnXclYV.js → xsl-DGNZQAUu.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-CmfInPqa.js → xychartDiagram-2RQKCTM6-L7M4YSvw.js} +1 -1
- package/dist/client/assets/{yaml-CjjyUhfg.js → yaml-Cm8mwIB7.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/{completions-7YSX1neu.mjs → completions-2aHVTmiJ.mjs} +17 -0
- package/dist/completions-CYa5usLb.mjs +2 -0
- package/dist/{mcp-DhynPewa.mjs → mcp-DoNBucix.mjs} +403 -6
- package/dist/mockup-format-D4Ln0WxJ.mjs +327 -0
- package/dist/native/tui-darwin-arm64/diffing-tui +0 -0
- package/dist/native/tui-darwin-x64/diffing-tui +0 -0
- package/dist/native/tui-linux-arm64-gnu/diffing-tui +0 -0
- package/dist/native/tui-linux-arm64-musl/diffing-tui +0 -0
- package/dist/native/tui-linux-x64-gnu/diffing-tui +0 -0
- package/dist/native/tui-linux-x64-musl/diffing-tui +0 -0
- package/dist/native/tui-win32-x64-msvc/diffing-tui.exe +0 -0
- package/dist/{review-export-GW4KNsGN.mjs → review-export-DoST2oPt.mjs} +1 -1
- package/dist/{server-CEbp7K-k.mjs → server-BRQdb64n.mjs} +1727 -49
- package/dist/{setup-BnS_rSxK.mjs → setup-BwWZ9Fzq.mjs} +1 -1
- package/extensions/pi/index.ts +452 -5
- package/package.json +1 -1
- package/dist/client/assets/channel-DsuXeLi4.js +0 -1
- package/dist/client/assets/chunk-QZHKN3VN-D5b3mBJ2.js +0 -1
- package/dist/client/assets/chunk-WU5MYG2G-C1Pa4Y04.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-DCnVfYt-.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BPa1Jkt-.js +0 -1
- package/dist/client/assets/index-BR6EGJ-g.css +0 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-DP6swlL9.js +0 -1
- package/dist/completions-5rtfoxB9.mjs +0 -2
- package/dist/plan-format-BwJh5JSE.mjs +0 -144
- /package/dist/{comment-format-B85NHZnG.mjs → comment-format-D4mCqr7T.mjs} +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { f as getProjectStorageDir } from "./git-BGj31GX-.mjs";
|
|
1
|
+
import { f as getProjectStorageDir, h as getRepoRoot } from "./git-BGj31GX-.mjs";
|
|
2
2
|
import { i as loadSettings, n as formatModeLabel, s as saveSettings } from "./settings-DkPDB_hS.mjs";
|
|
3
|
-
import { t as
|
|
4
|
-
import {
|
|
3
|
+
import { f as slugifyScreenId, r as formatPlanReview, t as formatMockupReview } from "./mockup-format-D4Ln0WxJ.mjs";
|
|
4
|
+
import { t as formatComments } from "./comment-format-D4mCqr7T.mjs";
|
|
5
5
|
import { u as resolveActiveServerLock, x as SESSION_TOKEN_HEADER } from "./server-lock-CdaUNZyX.mjs";
|
|
6
6
|
import { i as reviewSessionUrl, t as appendSessionToken } from "./session-url-B9FOnF3F.mjs";
|
|
7
7
|
import { a as CLI_AWAIT_REVIEW_TIMEOUT_HINT, i as CLI_AWAIT_PLAN_TIMEOUT_HINT, o as CLI_PLAN_SUBMIT_PARK_HINT } from "./handoff-DcShCxWJ.mjs";
|
|
8
|
-
import { join } from "node:path";
|
|
8
|
+
import { basename, join, resolve } from "node:path";
|
|
9
9
|
import { parseArgs } from "node:util";
|
|
10
|
-
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
10
|
+
import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
|
|
11
11
|
//#region src/cli-agent.ts
|
|
12
12
|
/**
|
|
13
13
|
* Agent-facing `diffing` subcommands. These make the user→agent handoff
|
|
@@ -48,6 +48,17 @@ function baseUrl() {
|
|
|
48
48
|
}
|
|
49
49
|
/** Attach session credentials while preserving ordinary web calls. */
|
|
50
50
|
function apiFetch(input, init = {}) {
|
|
51
|
+
let target;
|
|
52
|
+
try {
|
|
53
|
+
target = new URL(input instanceof Request ? input.url : input instanceof URL ? input.href : input);
|
|
54
|
+
} catch {
|
|
55
|
+
return Promise.reject(/* @__PURE__ */ new Error("Invalid diffing API URL"));
|
|
56
|
+
}
|
|
57
|
+
if (![
|
|
58
|
+
"127.0.0.1",
|
|
59
|
+
"localhost",
|
|
60
|
+
"::1"
|
|
61
|
+
].includes(target.hostname)) throw new Error(`Refusing non-loopback diffing API URL: ${target.origin}`);
|
|
51
62
|
const headers = new Headers(init.headers);
|
|
52
63
|
if (activeCapability) headers.set("X-Diffing-Capability", activeCapability);
|
|
53
64
|
if (activeAuthToken) headers.set(SESSION_TOKEN_HEADER, activeAuthToken);
|
|
@@ -379,7 +390,7 @@ async function comments(args) {
|
|
|
379
390
|
}
|
|
380
391
|
if (values.json || format === "json") process.stdout.write(JSON.stringify(selected, null, 2) + "\n");
|
|
381
392
|
else if (format === "markdown" || format === "md") {
|
|
382
|
-
const { formatCommentsMarkdown } = await import("./review-export-
|
|
393
|
+
const { formatCommentsMarkdown } = await import("./review-export-DoST2oPt.mjs");
|
|
383
394
|
process.stdout.write(formatCommentsMarkdown(selected) + "\n");
|
|
384
395
|
} else process.stdout.write(formatComments(selected) + "\n");
|
|
385
396
|
return EXIT_OK;
|
|
@@ -623,7 +634,7 @@ async function planShow(args) {
|
|
|
623
634
|
return 1;
|
|
624
635
|
}
|
|
625
636
|
const plan = await res.json();
|
|
626
|
-
const requestedVersion = values.version
|
|
637
|
+
const requestedVersion = values.version === void 0 ? void 0 : Number(values.version);
|
|
627
638
|
if (requestedVersion !== void 0 && (!Number.isFinite(requestedVersion) || requestedVersion < 1)) {
|
|
628
639
|
console.error(`--version must be a positive integer.`);
|
|
629
640
|
return EXIT_USAGE;
|
|
@@ -645,7 +656,7 @@ async function planVersions(args) {
|
|
|
645
656
|
allowPositionals: true
|
|
646
657
|
});
|
|
647
658
|
const base = baseUrl();
|
|
648
|
-
|
|
659
|
+
const planId = positionals[0];
|
|
649
660
|
if (!planId) {
|
|
650
661
|
console.error("Usage: diffing plan versions <id> [--json]");
|
|
651
662
|
return EXIT_USAGE;
|
|
@@ -833,7 +844,7 @@ See docs/getting-started.md for the full walkthrough.`);
|
|
|
833
844
|
console.error(`Unknown setup action: ${action}`);
|
|
834
845
|
return EXIT_USAGE;
|
|
835
846
|
}
|
|
836
|
-
const { runSetup } = await import("./setup-
|
|
847
|
+
const { runSetup } = await import("./setup-BwWZ9Fzq.mjs");
|
|
837
848
|
return runSetup({
|
|
838
849
|
yes,
|
|
839
850
|
check,
|
|
@@ -869,7 +880,7 @@ async function completion(args) {
|
|
|
869
880
|
console.error("Usage: diffing completion <bash|zsh|fish>");
|
|
870
881
|
return EXIT_USAGE;
|
|
871
882
|
}
|
|
872
|
-
const { completionFor } = await import("./completions-
|
|
883
|
+
const { completionFor } = await import("./completions-CYa5usLb.mjs");
|
|
873
884
|
const script = completionFor(shell);
|
|
874
885
|
if (!script) {
|
|
875
886
|
console.error(`Unknown shell: ${shell}. Use bash, zsh, or fish.`);
|
|
@@ -1021,7 +1032,7 @@ async function progress(args) {
|
|
|
1021
1032
|
model: values.model,
|
|
1022
1033
|
agentId: values["agent-id"],
|
|
1023
1034
|
commentId: values["comment-id"],
|
|
1024
|
-
pct: values.pct
|
|
1035
|
+
pct: values.pct == null ? void 0 : Number(values.pct)
|
|
1025
1036
|
})
|
|
1026
1037
|
});
|
|
1027
1038
|
if (!res) return EXIT_NO_SERVER;
|
|
@@ -1032,6 +1043,720 @@ async function progress(args) {
|
|
|
1032
1043
|
}
|
|
1033
1044
|
return EXIT_OK;
|
|
1034
1045
|
}
|
|
1046
|
+
const CLI_MOCKUP_SUBMIT_PARK_HINT = "Async handoff: share the URL above. Use --wait / `diffing mockup await` only when the human is reviewing now or asked you to block.";
|
|
1047
|
+
async function pollMockupDecision(base, timeoutMs, sinceRound = 0) {
|
|
1048
|
+
const deadline = Date.now() + timeoutMs;
|
|
1049
|
+
while (Date.now() < deadline) {
|
|
1050
|
+
const remaining = Math.max(deadline - Date.now(), 0);
|
|
1051
|
+
const res = await tryApiFetch(`${base}/api/mockup-review/await?sinceRound=${sinceRound}&timeoutMs=${Math.min(remaining, 25e3)}`);
|
|
1052
|
+
if (!res) return EXIT_NO_SERVER;
|
|
1053
|
+
if (!res.ok) {
|
|
1054
|
+
console.error(`Failed to await mockup review: HTTP ${res.status}`);
|
|
1055
|
+
return 1;
|
|
1056
|
+
}
|
|
1057
|
+
const result = await res.json();
|
|
1058
|
+
if (result.status === "released" && result.payload) {
|
|
1059
|
+
if (result.payload.reviewXml) process.stdout.write(result.payload.reviewXml + "\n");
|
|
1060
|
+
console.error(`DIFFING_MOCKUP_DECISION=${result.payload.decision}`);
|
|
1061
|
+
console.error(`DIFFING_MOCKUP_ROUND=${result.payload.round}`);
|
|
1062
|
+
return EXIT_OK;
|
|
1063
|
+
}
|
|
1064
|
+
sinceRound = result.round ?? sinceRound;
|
|
1065
|
+
}
|
|
1066
|
+
console.error("DIFFING_MOCKUP_AWAIT_TIMEOUT");
|
|
1067
|
+
return EXIT_AWAIT_TIMEOUT;
|
|
1068
|
+
}
|
|
1069
|
+
async function screensFromCli(file, screenFlags) {
|
|
1070
|
+
if (screenFlags && screenFlags.length > 0) {
|
|
1071
|
+
const screens = [];
|
|
1072
|
+
for (const flag of screenFlags) {
|
|
1073
|
+
const eq = flag.indexOf("=");
|
|
1074
|
+
if (eq <= 0) return { error: `--screen must be id=path (got ${flag})` };
|
|
1075
|
+
const id = slugifyScreenId(flag.slice(0, eq));
|
|
1076
|
+
if (!id) return { error: `Invalid screen id in ${flag}` };
|
|
1077
|
+
const path = resolve(flag.slice(eq + 1));
|
|
1078
|
+
try {
|
|
1079
|
+
const html = (await readFile(path, "utf-8")).replace(/\r\n/g, "\n");
|
|
1080
|
+
screens.push({
|
|
1081
|
+
id,
|
|
1082
|
+
html
|
|
1083
|
+
});
|
|
1084
|
+
} catch (err) {
|
|
1085
|
+
return { error: `Failed to read ${path}: ${err?.message ?? err}` };
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
return { screens };
|
|
1089
|
+
}
|
|
1090
|
+
if (!file || file === "-") {
|
|
1091
|
+
const html = (await readStdin()).replace(/\r\n/g, "\n");
|
|
1092
|
+
if (!html.trim()) return { error: "A mockup HTML body is required (file, dir, --screen, or stdin)." };
|
|
1093
|
+
return { html };
|
|
1094
|
+
}
|
|
1095
|
+
const abs = resolve(file);
|
|
1096
|
+
let st;
|
|
1097
|
+
try {
|
|
1098
|
+
st = await stat(abs);
|
|
1099
|
+
} catch (err) {
|
|
1100
|
+
return { error: `Failed to read ${file}: ${err?.message ?? err}` };
|
|
1101
|
+
}
|
|
1102
|
+
if (st.isDirectory()) {
|
|
1103
|
+
const names = (await readdir(abs)).filter((n) => /\.html?$/i.test(n));
|
|
1104
|
+
names.sort((a, b) => {
|
|
1105
|
+
if (a.toLowerCase() === "index.html") return -1;
|
|
1106
|
+
if (b.toLowerCase() === "index.html") return 1;
|
|
1107
|
+
return a.localeCompare(b);
|
|
1108
|
+
});
|
|
1109
|
+
if (names.length === 0) return { error: `No HTML files in ${abs}` };
|
|
1110
|
+
const screens = [];
|
|
1111
|
+
for (const name of names) {
|
|
1112
|
+
const id = slugifyScreenId(name);
|
|
1113
|
+
if (!id) continue;
|
|
1114
|
+
const html = (await readFile(join(abs, name), "utf-8")).replace(/\r\n/g, "\n");
|
|
1115
|
+
screens.push({
|
|
1116
|
+
id,
|
|
1117
|
+
html
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
if (screens.length === 0) return { error: `No valid screen ids in ${abs}` };
|
|
1121
|
+
return {
|
|
1122
|
+
screens,
|
|
1123
|
+
source: abs
|
|
1124
|
+
};
|
|
1125
|
+
}
|
|
1126
|
+
const html = (await readFile(abs, "utf-8")).replace(/\r\n/g, "\n");
|
|
1127
|
+
if (!html.trim()) return { error: `Empty HTML file ${file}` };
|
|
1128
|
+
return {
|
|
1129
|
+
html,
|
|
1130
|
+
source: abs
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
function warnMockupPathsInRepo(paths) {
|
|
1134
|
+
let root;
|
|
1135
|
+
try {
|
|
1136
|
+
root = getRepoRoot();
|
|
1137
|
+
} catch {
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
const storage = getProjectStorageDir();
|
|
1141
|
+
const rootPrefix = root.endsWith("/") ? root : `${root}/`;
|
|
1142
|
+
const storagePrefix = storage.endsWith("/") ? storage : `${storage}/`;
|
|
1143
|
+
for (const raw of paths) {
|
|
1144
|
+
const abs = resolve(raw);
|
|
1145
|
+
if (abs === storage || abs.startsWith(storagePrefix)) continue;
|
|
1146
|
+
if (abs === root || abs.startsWith(rootPrefix)) console.error(`Warning: ${abs} is inside the consumer repo. Never write diffing mockups into the working tree. Submit HTML via stdin or MCP submit_mockup({ html }), or stage files under ${storage}/mockup-sources/.`);
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
async function mockupSubmit(args) {
|
|
1150
|
+
const { values, positionals } = parseArgs({
|
|
1151
|
+
args,
|
|
1152
|
+
options: {
|
|
1153
|
+
title: { type: "string" },
|
|
1154
|
+
source: {
|
|
1155
|
+
type: "string",
|
|
1156
|
+
short: "s"
|
|
1157
|
+
},
|
|
1158
|
+
model: {
|
|
1159
|
+
type: "string",
|
|
1160
|
+
short: "m"
|
|
1161
|
+
},
|
|
1162
|
+
id: { type: "string" },
|
|
1163
|
+
wait: {
|
|
1164
|
+
type: "boolean",
|
|
1165
|
+
short: "w"
|
|
1166
|
+
},
|
|
1167
|
+
timeout: {
|
|
1168
|
+
type: "string",
|
|
1169
|
+
short: "t"
|
|
1170
|
+
},
|
|
1171
|
+
screen: {
|
|
1172
|
+
type: "string",
|
|
1173
|
+
multiple: true
|
|
1174
|
+
}
|
|
1175
|
+
},
|
|
1176
|
+
allowPositionals: true
|
|
1177
|
+
});
|
|
1178
|
+
warnMockupPathsInRepo([...positionals[0] && positionals[0] !== "-" ? [positionals[0]] : [], ...(values.screen ?? []).map((flag) => {
|
|
1179
|
+
const eq = flag.indexOf("=");
|
|
1180
|
+
return eq > 0 ? flag.slice(eq + 1) : "";
|
|
1181
|
+
}).filter(Boolean)]);
|
|
1182
|
+
const parsed = await screensFromCli(positionals[0], values.screen);
|
|
1183
|
+
if (parsed.error) {
|
|
1184
|
+
console.error(parsed.error);
|
|
1185
|
+
return EXIT_USAGE;
|
|
1186
|
+
}
|
|
1187
|
+
const title = values.title || (positionals[0] && positionals[0] !== "-" ? basename(positionals[0]).replace(/\.html?$/i, "") : "Untitled mockup");
|
|
1188
|
+
const base = baseUrl();
|
|
1189
|
+
let sinceRound = 0;
|
|
1190
|
+
if (values.wait) {
|
|
1191
|
+
const statusRes = await tryApiFetch(`${base}/api/mockup-review/status`);
|
|
1192
|
+
if (statusRes?.ok) sinceRound = (await statusRes.json()).round ?? 0;
|
|
1193
|
+
}
|
|
1194
|
+
const submitRes = await tryApiFetch(`${base}/api/mockups`, {
|
|
1195
|
+
method: "POST",
|
|
1196
|
+
headers: { "Content-Type": "application/json" },
|
|
1197
|
+
body: JSON.stringify({
|
|
1198
|
+
id: values.id,
|
|
1199
|
+
title,
|
|
1200
|
+
html: parsed.html,
|
|
1201
|
+
screens: parsed.screens,
|
|
1202
|
+
source: values.source || parsed.source,
|
|
1203
|
+
model: values.model
|
|
1204
|
+
})
|
|
1205
|
+
});
|
|
1206
|
+
if (!submitRes) return EXIT_NO_SERVER;
|
|
1207
|
+
if (!submitRes.ok) {
|
|
1208
|
+
const err = await submitRes.json().catch(() => ({ error: `HTTP ${submitRes.status}` }));
|
|
1209
|
+
console.error(`Failed to submit mockup: ${err.error ?? `HTTP ${submitRes.status}`}`);
|
|
1210
|
+
return 1;
|
|
1211
|
+
}
|
|
1212
|
+
const mockup = await submitRes.json();
|
|
1213
|
+
console.error(`Submitted mockup ${mockup.id} (v${mockup.version}) — review at ${appendSessionToken(`${base}/mockup/${mockup.id}`, activeAuthToken)}`);
|
|
1214
|
+
if (mockup.sourcePath) console.error(`Source path: ${mockup.sourcePath}`);
|
|
1215
|
+
if (!values.wait) {
|
|
1216
|
+
console.error(CLI_MOCKUP_SUBMIT_PARK_HINT);
|
|
1217
|
+
process.stdout.write(mockup.id + "\n");
|
|
1218
|
+
return EXIT_OK;
|
|
1219
|
+
}
|
|
1220
|
+
const timeoutSeconds = parseTimeoutSeconds(values.timeout);
|
|
1221
|
+
if (timeoutSeconds === null) return EXIT_USAGE;
|
|
1222
|
+
return pollMockupDecision(base, timeoutSeconds * 1e3, sinceRound);
|
|
1223
|
+
}
|
|
1224
|
+
async function mockupAwait(args) {
|
|
1225
|
+
const { values } = parseArgs({
|
|
1226
|
+
args,
|
|
1227
|
+
options: { timeout: {
|
|
1228
|
+
type: "string",
|
|
1229
|
+
short: "t"
|
|
1230
|
+
} },
|
|
1231
|
+
allowPositionals: false
|
|
1232
|
+
});
|
|
1233
|
+
const timeoutSeconds = parseTimeoutSeconds(values.timeout);
|
|
1234
|
+
if (timeoutSeconds === null) return EXIT_USAGE;
|
|
1235
|
+
return pollMockupDecision(baseUrl(), timeoutSeconds * 1e3);
|
|
1236
|
+
}
|
|
1237
|
+
async function mockupList(args) {
|
|
1238
|
+
const { values } = parseArgs({
|
|
1239
|
+
args,
|
|
1240
|
+
options: { json: { type: "boolean" } },
|
|
1241
|
+
allowPositionals: false
|
|
1242
|
+
});
|
|
1243
|
+
const res = await tryApiFetch(`${baseUrl()}/api/mockups`);
|
|
1244
|
+
if (!res) return EXIT_NO_SERVER;
|
|
1245
|
+
if (!res.ok) {
|
|
1246
|
+
console.error(`Failed to list mockups: HTTP ${res.status}`);
|
|
1247
|
+
return 1;
|
|
1248
|
+
}
|
|
1249
|
+
const all = await res.json();
|
|
1250
|
+
if (values.json) {
|
|
1251
|
+
process.stdout.write(JSON.stringify(all, null, 2) + "\n");
|
|
1252
|
+
return EXIT_OK;
|
|
1253
|
+
}
|
|
1254
|
+
if (all.length === 0) {
|
|
1255
|
+
console.error("No mockups submitted yet.");
|
|
1256
|
+
return EXIT_OK;
|
|
1257
|
+
}
|
|
1258
|
+
for (const m of all) {
|
|
1259
|
+
const open = (m.comments ?? []).filter((c) => c.status === "open").length;
|
|
1260
|
+
process.stdout.write(`${m.id}\t[${m.decision}]\tv${m.version}\t${m.screens.length} screen(s)\t${open} open\t${m.title}\n`);
|
|
1261
|
+
}
|
|
1262
|
+
return EXIT_OK;
|
|
1263
|
+
}
|
|
1264
|
+
async function mockupShow(args) {
|
|
1265
|
+
const { values, positionals } = parseArgs({
|
|
1266
|
+
args,
|
|
1267
|
+
options: {
|
|
1268
|
+
json: { type: "boolean" },
|
|
1269
|
+
version: { type: "string" }
|
|
1270
|
+
},
|
|
1271
|
+
allowPositionals: true
|
|
1272
|
+
});
|
|
1273
|
+
const base = baseUrl();
|
|
1274
|
+
let mockupId = positionals[0];
|
|
1275
|
+
if (!mockupId) {
|
|
1276
|
+
const listRes = await tryApiFetch(`${base}/api/mockups`);
|
|
1277
|
+
if (!listRes) return EXIT_NO_SERVER;
|
|
1278
|
+
const all = listRes.ok ? await listRes.json() : [];
|
|
1279
|
+
if (all.length === 0) {
|
|
1280
|
+
console.error("No mockups submitted yet.");
|
|
1281
|
+
return EXIT_NOT_FOUND;
|
|
1282
|
+
}
|
|
1283
|
+
mockupId = all[all.length - 1].id;
|
|
1284
|
+
}
|
|
1285
|
+
const res = await tryApiFetch(`${base}/api/mockups/${mockupId}`);
|
|
1286
|
+
if (!res) return EXIT_NO_SERVER;
|
|
1287
|
+
if (res.status === 404) {
|
|
1288
|
+
console.error(`Mockup ${mockupId} not found.`);
|
|
1289
|
+
return EXIT_NOT_FOUND;
|
|
1290
|
+
}
|
|
1291
|
+
if (!res.ok) {
|
|
1292
|
+
console.error(`Failed to load mockup: HTTP ${res.status}`);
|
|
1293
|
+
return 1;
|
|
1294
|
+
}
|
|
1295
|
+
const mockup = await res.json();
|
|
1296
|
+
const requestedVersion = values.version === void 0 ? void 0 : Number(values.version);
|
|
1297
|
+
if (requestedVersion !== void 0 && (!Number.isFinite(requestedVersion) || requestedVersion < 1)) {
|
|
1298
|
+
console.error(`--version must be a positive integer.`);
|
|
1299
|
+
return EXIT_USAGE;
|
|
1300
|
+
}
|
|
1301
|
+
if (values.json) process.stdout.write(JSON.stringify(mockup, null, 2) + "\n");
|
|
1302
|
+
else process.stdout.write(formatMockupReview(mockup, { viewingVersion: requestedVersion }) + "\n");
|
|
1303
|
+
return EXIT_OK;
|
|
1304
|
+
}
|
|
1305
|
+
async function mockupVersions(args) {
|
|
1306
|
+
const { values, positionals } = parseArgs({
|
|
1307
|
+
args,
|
|
1308
|
+
options: { json: { type: "boolean" } },
|
|
1309
|
+
allowPositionals: true
|
|
1310
|
+
});
|
|
1311
|
+
const id = positionals[0];
|
|
1312
|
+
if (!id) {
|
|
1313
|
+
console.error("Usage: diffing mockup versions <id>");
|
|
1314
|
+
return EXIT_USAGE;
|
|
1315
|
+
}
|
|
1316
|
+
const res = await tryApiFetch(`${baseUrl()}/api/mockups/${id}/versions`);
|
|
1317
|
+
if (!res) return EXIT_NO_SERVER;
|
|
1318
|
+
if (res.status === 404) {
|
|
1319
|
+
console.error(`Mockup ${id} not found.`);
|
|
1320
|
+
return EXIT_NOT_FOUND;
|
|
1321
|
+
}
|
|
1322
|
+
if (!res.ok) {
|
|
1323
|
+
console.error(`Failed to list versions: HTTP ${res.status}`);
|
|
1324
|
+
return 1;
|
|
1325
|
+
}
|
|
1326
|
+
const versions = await res.json();
|
|
1327
|
+
if (values.json) {
|
|
1328
|
+
process.stdout.write(JSON.stringify(versions, null, 2) + "\n");
|
|
1329
|
+
return EXIT_OK;
|
|
1330
|
+
}
|
|
1331
|
+
for (const v of versions) process.stdout.write(`v${v.version}\t${v.title}\n`);
|
|
1332
|
+
return EXIT_OK;
|
|
1333
|
+
}
|
|
1334
|
+
async function mockupReply(args) {
|
|
1335
|
+
const { values, positionals } = parseArgs({
|
|
1336
|
+
args,
|
|
1337
|
+
options: {
|
|
1338
|
+
body: {
|
|
1339
|
+
type: "string",
|
|
1340
|
+
short: "b"
|
|
1341
|
+
},
|
|
1342
|
+
model: {
|
|
1343
|
+
type: "string",
|
|
1344
|
+
short: "m"
|
|
1345
|
+
}
|
|
1346
|
+
},
|
|
1347
|
+
allowPositionals: true
|
|
1348
|
+
});
|
|
1349
|
+
const commentId = positionals[0];
|
|
1350
|
+
if (!commentId) {
|
|
1351
|
+
console.error("Usage: diffing mockup reply <comment-id> --body \"...\"");
|
|
1352
|
+
return EXIT_USAGE;
|
|
1353
|
+
}
|
|
1354
|
+
let body = values.body;
|
|
1355
|
+
if (!body) body = await readStdin();
|
|
1356
|
+
if (!body?.trim()) {
|
|
1357
|
+
console.error("A reply body is required (--body or stdin).");
|
|
1358
|
+
return EXIT_USAGE;
|
|
1359
|
+
}
|
|
1360
|
+
const listRes = await tryApiFetch(`${baseUrl()}/api/mockups?include=comments`);
|
|
1361
|
+
if (!listRes) return EXIT_NO_SERVER;
|
|
1362
|
+
const mockup = (listRes.ok ? await listRes.json() : []).find((m) => (m.comments ?? []).some((c) => c.id === commentId));
|
|
1363
|
+
if (!mockup) {
|
|
1364
|
+
console.error(`Comment ${commentId} not found.`);
|
|
1365
|
+
return EXIT_NOT_FOUND;
|
|
1366
|
+
}
|
|
1367
|
+
const res = await tryApiFetch(`${baseUrl()}/api/mockups/${mockup.id}/comments/${commentId}/replies`, {
|
|
1368
|
+
method: "POST",
|
|
1369
|
+
headers: { "Content-Type": "application/json" },
|
|
1370
|
+
body: JSON.stringify({
|
|
1371
|
+
body,
|
|
1372
|
+
model: values.model,
|
|
1373
|
+
role: "agent"
|
|
1374
|
+
})
|
|
1375
|
+
});
|
|
1376
|
+
if (!res) return EXIT_NO_SERVER;
|
|
1377
|
+
if (!res.ok) {
|
|
1378
|
+
console.error(`Failed to reply: HTTP ${res.status}`);
|
|
1379
|
+
return 1;
|
|
1380
|
+
}
|
|
1381
|
+
return EXIT_OK;
|
|
1382
|
+
}
|
|
1383
|
+
async function mockupResolve(args) {
|
|
1384
|
+
const { positionals } = parseArgs({
|
|
1385
|
+
args,
|
|
1386
|
+
allowPositionals: true
|
|
1387
|
+
});
|
|
1388
|
+
const commentId = positionals[0];
|
|
1389
|
+
if (!commentId) {
|
|
1390
|
+
console.error("Usage: diffing mockup resolve <comment-id>");
|
|
1391
|
+
return EXIT_USAGE;
|
|
1392
|
+
}
|
|
1393
|
+
const listRes = await tryApiFetch(`${baseUrl()}/api/mockups?include=comments`);
|
|
1394
|
+
if (!listRes) return EXIT_NO_SERVER;
|
|
1395
|
+
const mockup = (listRes.ok ? await listRes.json() : []).find((m) => (m.comments ?? []).some((c) => c.id === commentId));
|
|
1396
|
+
if (!mockup) {
|
|
1397
|
+
console.error(`Comment ${commentId} not found.`);
|
|
1398
|
+
return EXIT_NOT_FOUND;
|
|
1399
|
+
}
|
|
1400
|
+
const res = await tryApiFetch(`${baseUrl()}/api/mockups/${mockup.id}/comments/${commentId}`, {
|
|
1401
|
+
method: "PUT",
|
|
1402
|
+
headers: { "Content-Type": "application/json" },
|
|
1403
|
+
body: JSON.stringify({ status: "resolved" })
|
|
1404
|
+
});
|
|
1405
|
+
if (!res) return EXIT_NO_SERVER;
|
|
1406
|
+
if (!res.ok) {
|
|
1407
|
+
console.error(`Failed to resolve: HTTP ${res.status}`);
|
|
1408
|
+
return 1;
|
|
1409
|
+
}
|
|
1410
|
+
return EXIT_OK;
|
|
1411
|
+
}
|
|
1412
|
+
async function latestMockupId(base) {
|
|
1413
|
+
const listRes = await tryApiFetch(`${base}/api/mockups`);
|
|
1414
|
+
if (!listRes || !listRes.ok) return null;
|
|
1415
|
+
const all = await listRes.json();
|
|
1416
|
+
if (all.length === 0) return null;
|
|
1417
|
+
return all[all.length - 1].id;
|
|
1418
|
+
}
|
|
1419
|
+
async function mockupOpErrorMessage(res) {
|
|
1420
|
+
const body = await res.json().catch(() => ({}));
|
|
1421
|
+
if (body.code === "version-mismatch") return `Mockup version mismatch: current v${body.currentVersion}, expected v${body.expectedVersion}. Retry with --expected-version ${body.currentVersion}.`;
|
|
1422
|
+
return body.error ?? `HTTP ${res.status}`;
|
|
1423
|
+
}
|
|
1424
|
+
async function mockupInspect(args) {
|
|
1425
|
+
const { values, positionals } = parseArgs({
|
|
1426
|
+
args,
|
|
1427
|
+
options: {
|
|
1428
|
+
status: { type: "string" },
|
|
1429
|
+
screen: { type: "string" },
|
|
1430
|
+
viewport: { type: "string" },
|
|
1431
|
+
version: { type: "string" },
|
|
1432
|
+
id: { type: "string" },
|
|
1433
|
+
cursor: { type: "string" },
|
|
1434
|
+
limit: { type: "string" },
|
|
1435
|
+
context: { type: "string" },
|
|
1436
|
+
pretty: { type: "boolean" }
|
|
1437
|
+
},
|
|
1438
|
+
allowPositionals: true
|
|
1439
|
+
});
|
|
1440
|
+
const [view, mockupArg, ...extra] = positionals;
|
|
1441
|
+
if (!view || ![
|
|
1442
|
+
"summary",
|
|
1443
|
+
"comments",
|
|
1444
|
+
"comment",
|
|
1445
|
+
"screen"
|
|
1446
|
+
].includes(view) || extra.length > 0) {
|
|
1447
|
+
console.error(`Usage: diffing mockup inspect <summary|comments|comment|screen> [mockup-id] [options]
|
|
1448
|
+
|
|
1449
|
+
Read bounded mockup data as compact JSON (add --pretty for indented output).
|
|
1450
|
+
summary [mockup-id] — headline stats + screen list
|
|
1451
|
+
comments [mockup-id] [--status open|resolved] [--screen S] [--viewport desktop|tablet|mobile] [--version N] [--cursor N] [--limit N] [--context none|anchor|source]
|
|
1452
|
+
comment [mockup-id] --id <comment-id> [--context none|anchor|source]
|
|
1453
|
+
screen [mockup-id] [--cursor N] [--limit N]
|
|
1454
|
+
|
|
1455
|
+
context: none = metadata only; anchor = + locator fields (default); source = + contextHtml.`);
|
|
1456
|
+
return EXIT_USAGE;
|
|
1457
|
+
}
|
|
1458
|
+
const base = baseUrl();
|
|
1459
|
+
let mockupId = mockupArg;
|
|
1460
|
+
if (!mockupId) {
|
|
1461
|
+
mockupId = await latestMockupId(base) ?? "";
|
|
1462
|
+
if (!mockupId) {
|
|
1463
|
+
console.error("No mockups submitted yet.");
|
|
1464
|
+
return EXIT_NOT_FOUND;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
const params = new URLSearchParams();
|
|
1468
|
+
params.set("view", view);
|
|
1469
|
+
const numeric = (flag, name) => {
|
|
1470
|
+
const value = values[flag];
|
|
1471
|
+
if (typeof value !== "string") return true;
|
|
1472
|
+
if (!/^\d+$/.test(value)) {
|
|
1473
|
+
console.error(`--${name} must be a non-negative integer`);
|
|
1474
|
+
return false;
|
|
1475
|
+
}
|
|
1476
|
+
params.set(name, value);
|
|
1477
|
+
return true;
|
|
1478
|
+
};
|
|
1479
|
+
if (!numeric("cursor", "cursor")) return EXIT_USAGE;
|
|
1480
|
+
if (!numeric("limit", "limit")) return EXIT_USAGE;
|
|
1481
|
+
if (!numeric("version", "version")) return EXIT_USAGE;
|
|
1482
|
+
const str = (flag, name) => {
|
|
1483
|
+
const value = values[flag];
|
|
1484
|
+
if (typeof value === "string") params.set(name, value);
|
|
1485
|
+
};
|
|
1486
|
+
str("status", "status");
|
|
1487
|
+
str("screen", "screen");
|
|
1488
|
+
str("viewport", "viewport");
|
|
1489
|
+
str("id", "id");
|
|
1490
|
+
str("context", "context");
|
|
1491
|
+
const res = await tryApiFetch(`${base}/api/mockups/${encodeURIComponent(mockupId)}/inspect?${params.toString()}`);
|
|
1492
|
+
if (!res) return EXIT_NO_SERVER;
|
|
1493
|
+
if (res.status === 404) {
|
|
1494
|
+
console.error(`Mockup ${mockupId} not found.`);
|
|
1495
|
+
return EXIT_NOT_FOUND;
|
|
1496
|
+
}
|
|
1497
|
+
if (!res.ok) {
|
|
1498
|
+
const err = await res.json().catch(() => ({}));
|
|
1499
|
+
console.error(err.error ?? `HTTP ${res.status}`);
|
|
1500
|
+
return 1;
|
|
1501
|
+
}
|
|
1502
|
+
const data = await res.json();
|
|
1503
|
+
process.stdout.write(JSON.stringify(data, null, values.pretty ? 2 : void 0) + "\n");
|
|
1504
|
+
return EXIT_OK;
|
|
1505
|
+
}
|
|
1506
|
+
async function mockupScreenCmd(args) {
|
|
1507
|
+
const { values, positionals } = parseArgs({
|
|
1508
|
+
args,
|
|
1509
|
+
options: {
|
|
1510
|
+
file: { type: "string" },
|
|
1511
|
+
text: { type: "string" },
|
|
1512
|
+
replacement: { type: "string" },
|
|
1513
|
+
label: { type: "string" },
|
|
1514
|
+
"expected-version": { type: "string" }
|
|
1515
|
+
},
|
|
1516
|
+
allowPositionals: true
|
|
1517
|
+
});
|
|
1518
|
+
const [action, mockupId, screenId, ...extra] = positionals;
|
|
1519
|
+
if (!action || ![
|
|
1520
|
+
"upsert",
|
|
1521
|
+
"remove",
|
|
1522
|
+
"patch"
|
|
1523
|
+
].includes(action) || !mockupId || !screenId || extra.length > 0) {
|
|
1524
|
+
console.error(`Usage: diffing mockup screen <upsert|remove|patch> <mockup-id> <screen-id> [options]
|
|
1525
|
+
|
|
1526
|
+
One-screen revision. Version bumps on success; an --expected-version guard aborts with
|
|
1527
|
+
409 (no change) when the mockup moved on.
|
|
1528
|
+
upsert <id> <screen-id> --file <path> [--label L] [--expected-version N] # --file - = stdin
|
|
1529
|
+
remove <id> <screen-id> [--expected-version N]
|
|
1530
|
+
patch <id> <screen-id> --text <exact-text> --replacement <new-text> [--expected-version N]`);
|
|
1531
|
+
return EXIT_USAGE;
|
|
1532
|
+
}
|
|
1533
|
+
let expectedVersion;
|
|
1534
|
+
if (values["expected-version"] !== void 0) {
|
|
1535
|
+
if (!/^\d+$/.test(values["expected-version"])) {
|
|
1536
|
+
console.error("--expected-version must be a positive integer");
|
|
1537
|
+
return EXIT_USAGE;
|
|
1538
|
+
}
|
|
1539
|
+
expectedVersion = Number(values["expected-version"]);
|
|
1540
|
+
}
|
|
1541
|
+
const base = baseUrl();
|
|
1542
|
+
if (action === "upsert") {
|
|
1543
|
+
let html;
|
|
1544
|
+
const file = values.file;
|
|
1545
|
+
if (!file || file === "-") html = (await readStdin()).replace(/\r\n/g, "\n");
|
|
1546
|
+
else try {
|
|
1547
|
+
html = (await readFile(resolve(file), "utf-8")).replace(/\r\n/g, "\n");
|
|
1548
|
+
} catch (err) {
|
|
1549
|
+
console.error(`Failed to read ${file}: ${err?.message ?? err}`);
|
|
1550
|
+
return EXIT_USAGE;
|
|
1551
|
+
}
|
|
1552
|
+
if (!html.trim()) {
|
|
1553
|
+
console.error("Screen html is required (--file <path> or stdin).");
|
|
1554
|
+
return EXIT_USAGE;
|
|
1555
|
+
}
|
|
1556
|
+
const res = await tryApiFetch(`${base}/api/mockups/${encodeURIComponent(mockupId)}/screens/${encodeURIComponent(screenId)}`, {
|
|
1557
|
+
method: "PUT",
|
|
1558
|
+
headers: { "Content-Type": "application/json" },
|
|
1559
|
+
body: JSON.stringify({
|
|
1560
|
+
html,
|
|
1561
|
+
label: values.label,
|
|
1562
|
+
expectedVersion
|
|
1563
|
+
})
|
|
1564
|
+
});
|
|
1565
|
+
if (!res) return EXIT_NO_SERVER;
|
|
1566
|
+
if (!res.ok) {
|
|
1567
|
+
console.error(await mockupOpErrorMessage(res));
|
|
1568
|
+
return res.status === 404 ? EXIT_NOT_FOUND : 1;
|
|
1569
|
+
}
|
|
1570
|
+
const mockup = await res.json();
|
|
1571
|
+
console.error(`Upserted screen ${screenId} on ${mockupId} → v${mockup.version} (${mockup.screens.length} screens).`);
|
|
1572
|
+
return EXIT_OK;
|
|
1573
|
+
}
|
|
1574
|
+
if (action === "remove") {
|
|
1575
|
+
const qs = expectedVersion === void 0 ? "" : `?expectedVersion=${expectedVersion}`;
|
|
1576
|
+
const res = await tryApiFetch(`${base}/api/mockups/${encodeURIComponent(mockupId)}/screens/${encodeURIComponent(screenId)}${qs}`, { method: "DELETE" });
|
|
1577
|
+
if (!res) return EXIT_NO_SERVER;
|
|
1578
|
+
if (!res.ok) {
|
|
1579
|
+
console.error(await mockupOpErrorMessage(res));
|
|
1580
|
+
return res.status === 404 ? EXIT_NOT_FOUND : 1;
|
|
1581
|
+
}
|
|
1582
|
+
const mockup = await res.json();
|
|
1583
|
+
console.error(`Removed screen ${screenId} from ${mockupId} → v${mockup.version}.`);
|
|
1584
|
+
return EXIT_OK;
|
|
1585
|
+
}
|
|
1586
|
+
const text = values.text;
|
|
1587
|
+
const replacement = values.replacement;
|
|
1588
|
+
if (!text || replacement === void 0) {
|
|
1589
|
+
console.error("patch requires --text <exact-text> and --replacement <new-text>");
|
|
1590
|
+
return EXIT_USAGE;
|
|
1591
|
+
}
|
|
1592
|
+
const res = await tryApiFetch(`${base}/api/mockups/${encodeURIComponent(mockupId)}/screens/${encodeURIComponent(screenId)}`, {
|
|
1593
|
+
method: "PATCH",
|
|
1594
|
+
headers: { "Content-Type": "application/json" },
|
|
1595
|
+
body: JSON.stringify({
|
|
1596
|
+
expectedText: text,
|
|
1597
|
+
replacement,
|
|
1598
|
+
expectedVersion
|
|
1599
|
+
})
|
|
1600
|
+
});
|
|
1601
|
+
if (!res) return EXIT_NO_SERVER;
|
|
1602
|
+
if (!res.ok) {
|
|
1603
|
+
console.error(await mockupOpErrorMessage(res));
|
|
1604
|
+
return res.status === 404 ? EXIT_NOT_FOUND : 1;
|
|
1605
|
+
}
|
|
1606
|
+
const data = await res.json();
|
|
1607
|
+
console.error(`Patched ${screenId} on ${mockupId} (${data.occurrences} exact match(es)) → v${data.mockup.version}.`);
|
|
1608
|
+
return EXIT_OK;
|
|
1609
|
+
}
|
|
1610
|
+
async function mockupThreadsCmd(args) {
|
|
1611
|
+
const { values, positionals } = parseArgs({
|
|
1612
|
+
args,
|
|
1613
|
+
options: {
|
|
1614
|
+
body: {
|
|
1615
|
+
type: "string",
|
|
1616
|
+
short: "b"
|
|
1617
|
+
},
|
|
1618
|
+
model: {
|
|
1619
|
+
type: "string",
|
|
1620
|
+
short: "m"
|
|
1621
|
+
},
|
|
1622
|
+
id: { type: "string" }
|
|
1623
|
+
},
|
|
1624
|
+
allowPositionals: true
|
|
1625
|
+
});
|
|
1626
|
+
const [action, commentId, replyId, ...extra] = positionals;
|
|
1627
|
+
if (!(typeof action === "string" && [
|
|
1628
|
+
"reply",
|
|
1629
|
+
"edit",
|
|
1630
|
+
"delete",
|
|
1631
|
+
"resolve",
|
|
1632
|
+
"unresolve"
|
|
1633
|
+
].includes(action)) || !commentId || extra.length > 0) {
|
|
1634
|
+
console.error(`Usage: diffing mockup threads <reply|edit|delete|resolve|unresolve> ...
|
|
1635
|
+
|
|
1636
|
+
Atomic thread ops — each call is validated before apply through the batch endpoint.
|
|
1637
|
+
reply <comment-id> --body "..." [--model M] [--id mockup-id]
|
|
1638
|
+
edit <comment-id> [<reply-id>] --body "..." # with reply-id: edit the reply; without: edit the comment body
|
|
1639
|
+
delete <comment-id> [<reply-id>] # with reply-id: delete the reply; without: delete the comment
|
|
1640
|
+
resolve <comment-id>
|
|
1641
|
+
unresolve <comment-id>`);
|
|
1642
|
+
return EXIT_USAGE;
|
|
1643
|
+
}
|
|
1644
|
+
let body = values.body;
|
|
1645
|
+
if (action === "reply" || action === "edit") {
|
|
1646
|
+
if (body === void 0) {
|
|
1647
|
+
if (process.stdin.isTTY) {
|
|
1648
|
+
console.error(`threads ${action}: a body is required (--body <text> or stdin)`);
|
|
1649
|
+
return EXIT_USAGE;
|
|
1650
|
+
}
|
|
1651
|
+
body = (await readStdin()).trim();
|
|
1652
|
+
} else if (body === "-") body = (await readStdin()).trim();
|
|
1653
|
+
if (!body?.trim()) {
|
|
1654
|
+
console.error(`threads ${action}: a body is required (--body <text> or stdin)`);
|
|
1655
|
+
return EXIT_USAGE;
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
const base = baseUrl();
|
|
1659
|
+
let mockupId = values.id;
|
|
1660
|
+
if (!mockupId) {
|
|
1661
|
+
const listRes = await tryApiFetch(`${base}/api/mockups?include=comments`);
|
|
1662
|
+
if (!listRes) return EXIT_NO_SERVER;
|
|
1663
|
+
const found = (listRes.ok ? await listRes.json() : []).find((m) => (m.comments ?? []).some((c) => c.id === commentId));
|
|
1664
|
+
if (!found) {
|
|
1665
|
+
console.error(`Comment ${commentId} not found.`);
|
|
1666
|
+
return EXIT_NOT_FOUND;
|
|
1667
|
+
}
|
|
1668
|
+
mockupId = found.id;
|
|
1669
|
+
}
|
|
1670
|
+
const operations = [];
|
|
1671
|
+
if (action === "reply") operations.push({
|
|
1672
|
+
op: action,
|
|
1673
|
+
commentId,
|
|
1674
|
+
body,
|
|
1675
|
+
role: "agent",
|
|
1676
|
+
model: values.model
|
|
1677
|
+
});
|
|
1678
|
+
else if (action === "edit") operations.push(replyId ? {
|
|
1679
|
+
op: action,
|
|
1680
|
+
commentId,
|
|
1681
|
+
replyId,
|
|
1682
|
+
body
|
|
1683
|
+
} : {
|
|
1684
|
+
op: action,
|
|
1685
|
+
commentId,
|
|
1686
|
+
body
|
|
1687
|
+
});
|
|
1688
|
+
else if (action === "delete") operations.push(replyId ? {
|
|
1689
|
+
op: action,
|
|
1690
|
+
commentId,
|
|
1691
|
+
replyId
|
|
1692
|
+
} : {
|
|
1693
|
+
op: action,
|
|
1694
|
+
commentId
|
|
1695
|
+
});
|
|
1696
|
+
else operations.push({
|
|
1697
|
+
op: action,
|
|
1698
|
+
commentId
|
|
1699
|
+
});
|
|
1700
|
+
const res = await tryApiFetch(`${base}/api/mockups/${encodeURIComponent(mockupId)}/threads/batch`, {
|
|
1701
|
+
method: "POST",
|
|
1702
|
+
headers: { "Content-Type": "application/json" },
|
|
1703
|
+
body: JSON.stringify({ operations })
|
|
1704
|
+
});
|
|
1705
|
+
if (!res) return EXIT_NO_SERVER;
|
|
1706
|
+
if (!res.ok) {
|
|
1707
|
+
const err = await res.json().catch(() => ({}));
|
|
1708
|
+
console.error(err.error ?? `HTTP ${res.status}`);
|
|
1709
|
+
return res.status === 404 ? EXIT_NOT_FOUND : 1;
|
|
1710
|
+
}
|
|
1711
|
+
const newReplyId = (await res.json()).results[0]?.replyId;
|
|
1712
|
+
if (action === "reply") console.error(`Replied to ${commentId}${newReplyId ? ` (${newReplyId})` : ""}.`);
|
|
1713
|
+
else if (action === "edit") console.error(replyId ? `Edited reply ${replyId}.` : `Edited comment ${commentId}.`);
|
|
1714
|
+
else if (action === "delete") console.error(replyId ? `Deleted reply ${replyId}.` : `Deleted comment ${commentId}.`);
|
|
1715
|
+
else if (action === "resolve") console.error(`Resolved ${commentId}.`);
|
|
1716
|
+
else console.error(`Re-opened ${commentId}.`);
|
|
1717
|
+
return EXIT_OK;
|
|
1718
|
+
}
|
|
1719
|
+
async function mockupCommand(args) {
|
|
1720
|
+
const action = args[0];
|
|
1721
|
+
const rest = args.slice(1);
|
|
1722
|
+
if (args.includes("--help") || args.includes("-h") || !action) {
|
|
1723
|
+
console.log(`Usage: diffing mockup <submit|await|list|show|versions|reply|resolve|inspect|screen|threads> [options]
|
|
1724
|
+
|
|
1725
|
+
Submit HTML mockups for visual review. Same loop as plan review.
|
|
1726
|
+
Never write mockup HTML into the consumer git tree. Prefer stdin or MCP inline html.
|
|
1727
|
+
Staging files, if needed, go under ~/.diffing/<repo>/mockup-sources/ only.
|
|
1728
|
+
One state per screen: never tabs/accordions/toggles/modals/JS content-swapping — each variant is a separate screen.
|
|
1729
|
+
|
|
1730
|
+
submit [-] [--title T] [--screen id=path]... [--id ID] [--model M] [--wait]
|
|
1731
|
+
# or a path already under ~/.diffing/.../mockup-sources/
|
|
1732
|
+
await [--timeout N]
|
|
1733
|
+
list [--json]
|
|
1734
|
+
show [<id>] [--json] [--version N]
|
|
1735
|
+
versions <id> [--json]
|
|
1736
|
+
reply <comment-id> --body "..." [--model M]
|
|
1737
|
+
resolve <comment-id>
|
|
1738
|
+
inspect <summary|comments|comment|screen> [<id>] [--status S] [--screen S] [--viewport V] [--version N] [--id C] [--cursor N] [--limit N] [--context none|anchor|source] [--pretty]
|
|
1739
|
+
screen <upsert|remove|patch> <id> <screen-id> [--file P] [--text T] [--replacement R] [--expected-version N]
|
|
1740
|
+
threads <reply|edit|delete|resolve|unresolve> <comment-id> [<reply-id>] [--body "..."] [--model M] [--id mockup-id]
|
|
1741
|
+
`);
|
|
1742
|
+
return EXIT_OK;
|
|
1743
|
+
}
|
|
1744
|
+
switch (action) {
|
|
1745
|
+
case "submit": return mockupSubmit(rest);
|
|
1746
|
+
case "await": return mockupAwait(rest);
|
|
1747
|
+
case "list": return mockupList(rest);
|
|
1748
|
+
case "show": return mockupShow(rest);
|
|
1749
|
+
case "versions": return mockupVersions(rest);
|
|
1750
|
+
case "reply": return mockupReply(rest);
|
|
1751
|
+
case "resolve": return mockupResolve(rest);
|
|
1752
|
+
case "inspect": return mockupInspect(rest);
|
|
1753
|
+
case "screen": return mockupScreenCmd(rest);
|
|
1754
|
+
case "threads": return mockupThreadsCmd(rest);
|
|
1755
|
+
default:
|
|
1756
|
+
console.error(`Unknown mockup action: ${action}`);
|
|
1757
|
+
return EXIT_USAGE;
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1035
1760
|
async function runSubcommand(name, args) {
|
|
1036
1761
|
switch (name) {
|
|
1037
1762
|
case "await-review": return awaitReview(args);
|
|
@@ -1042,21 +1767,25 @@ async function runSubcommand(name, args) {
|
|
|
1042
1767
|
case "comments": return comments(args);
|
|
1043
1768
|
case "url": return url();
|
|
1044
1769
|
case "plan": return plan(args);
|
|
1045
|
-
case "
|
|
1770
|
+
case "mockup": return mockupCommand(args);
|
|
1771
|
+
case "update": {
|
|
1046
1772
|
const { runUpdateCommand } = await import("./update-check-ISaw61qS.mjs");
|
|
1047
1773
|
return runUpdateCommand();
|
|
1048
|
-
|
|
1049
|
-
|
|
1774
|
+
}
|
|
1775
|
+
case "gh": {
|
|
1776
|
+
const { runGhSubcommand } = await import("./cli-gh-2NEumKQB.mjs");
|
|
1050
1777
|
return runGhSubcommand(args);
|
|
1778
|
+
}
|
|
1051
1779
|
case "doctor": return doctor();
|
|
1052
1780
|
case "setup": return setup(args);
|
|
1053
1781
|
case "completion": return completion(args);
|
|
1054
1782
|
case "progress": return progress(args);
|
|
1055
1783
|
case "inspect": return inspect(args);
|
|
1056
1784
|
case "mode": return mode(args);
|
|
1057
|
-
case "sessions":
|
|
1785
|
+
case "sessions": {
|
|
1058
1786
|
const { runSessionsCommand } = await import("./session-manager-CUqF8hkP.mjs");
|
|
1059
1787
|
return runSessionsCommand(args);
|
|
1788
|
+
}
|
|
1060
1789
|
default:
|
|
1061
1790
|
console.error(`Unknown subcommand: ${name}`);
|
|
1062
1791
|
return EXIT_USAGE;
|