@a9n-shoji/rvw 0.3.0 → 0.3.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/CHANGELOG.md +39 -0
- package/README.md +29 -10
- package/dist/cli.mjs +974 -111
- package/dist/cli.mjs.map +4 -4
- package/dist/web/assets/CommentThread-CMXtuZ98.js +33 -0
- package/dist/web/assets/DocumentViewer-D-UGIxCU.js +1417 -0
- package/dist/web/assets/MarkdownTable-7Sm_sj1E.js +7 -0
- package/dist/web/assets/MermaidExpandedView-CyWRss2q.js +4 -0
- package/dist/web/assets/MermaidSurface-Dt2_Hu6n.js +344 -0
- package/dist/web/assets/WalkthroughViewer-CuJMrKOW.js +43 -0
- package/dist/web/assets/abnfDiagram-N423BO3Z-DjhFeHQj.js +1 -0
- package/dist/web/assets/architecture-TIHT7OUA-CsHfPErM.js +1 -0
- package/dist/web/assets/architectureDiagram-T3A2C74G-4zQ-4s9L.js +36 -0
- package/dist/web/assets/{blockDiagram-VBNYF7ZC-BBG7PXeg.js → blockDiagram-VBNYF7ZC-Bh91Tm8T.js} +1 -1
- package/dist/web/assets/{c4Diagram-5PPSVZJV-oLErQeqr.js → c4Diagram-5PPSVZJV-BHgLhSdB.js} +1 -1
- package/dist/web/assets/ccount-DFmD81E1.js +1 -0
- package/dist/web/assets/channel-BmC0cAv-.js +1 -0
- package/dist/web/assets/{chunk-2GRJ4B5K-Bknsyt9u.js → chunk-2GRJ4B5K-sTPzFBtk.js} +1 -1
- package/dist/web/assets/chunk-3NCLNEKW-k0AW8Qyp.js +1 -0
- package/dist/web/assets/{chunk-4I5QYGJK-D-Icvgxq.js → chunk-4I5QYGJK-q_8xEFmv.js} +1 -1
- package/dist/web/assets/chunk-5FCAYU7R-Dh5nylU8.js +1 -0
- package/dist/web/assets/chunk-5HE753X5-Bw-yg4kO.js +1 -0
- package/dist/web/assets/chunk-5JV3BV7I-Cy5pj3QY.js +1 -0
- package/dist/web/assets/{chunk-5RXB4S5H-B1iIyQwd.js → chunk-5RXB4S5H-BcuYQqlM.js} +1 -1
- package/dist/web/assets/chunk-5TONJI2A-DQOY3q1H.js +2 -0
- package/dist/web/assets/{chunk-6Q2QTUOP-C09OFw2-.js → chunk-6Q2QTUOP-DDI96JMg.js} +1 -1
- package/dist/web/assets/{chunk-7Z6QIM7H-BqCAUqX5.js → chunk-7Z6QIM7H-B8QX_5g4.js} +1 -1
- package/dist/web/assets/chunk-BIQX33UG-DZEsGuSn.js +1 -0
- package/dist/web/assets/chunk-CQNSW5MT-B8S09OIh.js +1 -0
- package/dist/web/assets/chunk-CYSBUYHQ-C1Rf4art.js +1 -0
- package/dist/web/assets/chunk-EMLP6XTP-RLD4nXpI.js +1 -0
- package/dist/web/assets/{chunk-GF5L2VYU-BHy3jGGE.js → chunk-GF5L2VYU-CJin2HQO.js} +1 -1
- package/dist/web/assets/{chunk-I66GZJ75-BBhE3jWF.js → chunk-I66GZJ75-CEntV2nF.js} +1 -1
- package/dist/web/assets/chunk-J7OUQ5F2-XLdTvjUm.js +2 -0
- package/dist/web/assets/chunk-JG7HCLWE-BYfiSaVt.js +2 -0
- package/dist/web/assets/{chunk-JQJVKLGR-DNslGDt7.js → chunk-JQJVKLGR-Bnum3gum.js} +3 -3
- package/dist/web/assets/{chunk-KBJHAD2P-J7tWEBhK.js → chunk-KBJHAD2P-DwPs20tJ.js} +1 -1
- package/dist/web/assets/chunk-MOZMSUNE-XVucA-n6.js +1 -0
- package/dist/web/assets/{chunk-NSK5VX7P-retcSoJp.js → chunk-NSK5VX7P-AmYQxFLu.js} +1 -1
- package/dist/web/assets/chunk-OSBZ3O6U-CrKZOUOr.js +1 -0
- package/dist/web/assets/chunk-QBLGF6JB-CxAyS2mW.js +1 -0
- package/dist/web/assets/{chunk-QR6OTTB3-DvFlp4db.js → chunk-QR6OTTB3-VIu9ZqqS.js} +1 -1
- package/dist/web/assets/chunk-R7FJI6CG-Cnn3gE-Y.js +1 -0
- package/dist/web/assets/chunk-U6XO7XAA-BFxjP5U3.js +2 -0
- package/dist/web/assets/{chunk-UBXNYLIW-gyX_iwb1.js → chunk-UBXNYLIW-D4XAD8w6.js} +1 -1
- package/dist/web/assets/{chunk-W5SLKNZC-BGNgHuYL.js → chunk-W5SLKNZC-B8QG_JAG.js} +1 -1
- package/dist/web/assets/{chunk-WRU74C26-66KXN6Rn.js → chunk-WRU74C26-CS8zeNym.js} +1 -1
- package/dist/web/assets/chunk-YOTPTUD7-D0vRKqYp.js +1 -0
- package/dist/web/assets/chunk-ZIRB5QZD-O39ZBUk3.js +32 -0
- package/dist/web/assets/classDiagram-JCYQIIEL-DyY7Kt3N.js +1 -0
- package/dist/web/assets/classDiagram-v2-OCEON4UE-DyY7Kt3N.js +1 -0
- package/dist/web/assets/cynefin-VYW2F7L2-Ds2Fw2Y0.js +1 -0
- package/dist/web/assets/cynefinDiagram-MW4NZA55-DaNC4kY7.js +62 -0
- package/dist/web/assets/{dagre-VZM6K2ZE-BTedug-5.js → dagre-VZM6K2ZE-DJ845MyA.js} +1 -1
- package/dist/web/assets/{diagram-7IWD3JNH-kSc1kTCk.js → diagram-7IWD3JNH-98E00vZR.js} +3 -3
- package/dist/web/assets/diagram-B4RE2ZJO-BpMQ8ico.js +3 -0
- package/dist/web/assets/diagram-LBJQPF4R-BZ8RNQpZ.js +24 -0
- package/dist/web/assets/diagram-Q27KOJAE-Bn1wtc7g.js +24 -0
- package/dist/web/assets/diagram-UB23O5K3-B314M-wb.js +41 -0
- package/dist/web/assets/dist-DCGa16l5.js +145 -0
- package/dist/web/assets/ebnfDiagram-BXEA7PRR-CqKM-cL0.js +1 -0
- package/dist/web/assets/{erDiagram-JOGREHBK-jm3RTuJX.js → erDiagram-JOGREHBK-CVMcNMlx.js} +1 -1
- package/dist/web/assets/eventmodeling-45OFAUF4-CLEiVx5s.js +1 -0
- package/dist/web/assets/flowDiagram-UKHOOZJN-8dur6GAS.js +1 -0
- package/dist/web/assets/{ganttDiagram-PKOTCBZU--GwSY0BM.js → ganttDiagram-PKOTCBZU-DALoGLHl.js} +1 -1
- package/dist/web/assets/gitGraph-TEB2WS4Q-CZFBqwW-.js +1 -0
- package/dist/web/assets/gitGraphDiagram-DS77QQ5N-BY_jOOb-.js +106 -0
- package/dist/web/assets/index-BNcvGFlf.css +1 -0
- package/dist/web/assets/index-BwIKbLJ1.js +11 -0
- package/dist/web/assets/info-DKCQHKI2--1InqQeT.js +1 -0
- package/dist/web/assets/infoDiagram-6WML65LV-CNMbrlEJ.js +2 -0
- package/dist/web/assets/{ishikawaDiagram-WSZJBQD7-ErnJ_7Sr.js → ishikawaDiagram-WSZJBQD7-NODY49Zb.js} +2 -2
- package/dist/web/assets/{journeyDiagram-NVQOT4AX-CWvooGdp.js → journeyDiagram-NVQOT4AX-v9CJWB8Y.js} +1 -1
- package/dist/web/assets/{kanban-definition-27J2QSJJ-DsIS6ipP.js → kanban-definition-27J2QSJJ-Cv2iL7No.js} +3 -3
- package/dist/web/assets/lib-p2IERBh0.js +9 -0
- package/dist/web/assets/{line-DCcVjraC.js → line-Dah7RomF.js} +1 -1
- package/dist/web/assets/mermaid-parser.core-BcQae2Lb.js +4 -0
- package/dist/web/assets/mermaid.core-BVyLgPb6.js +11 -0
- package/dist/web/assets/{mindmap-definition-FAOFIHXS-DdsB9lmP.js → mindmap-definition-FAOFIHXS-BD9fkU-f.js} +1 -1
- package/dist/web/assets/packet-7NZHBO7P-BGMXB0XL.js +1 -0
- package/dist/web/assets/pegDiagram-VL7TDLO6-D-HL9Pvp.js +1 -0
- package/dist/web/assets/pie-RZYD4A2V-DgYg3tCt.js +1 -0
- package/dist/web/assets/pieDiagram-7S7Q4E2Y-Sam5BEo-.js +39 -0
- package/dist/web/assets/preload-helper-Czpn1I53.js +1 -0
- package/dist/web/assets/{quadrantDiagram-CIZ2JOQS-CryFsz7r.js → quadrantDiagram-CIZ2JOQS-BNXhvOJb.js} +1 -1
- package/dist/web/assets/radar-I7S5WNFK-Ag-zp_Rq.js +1 -0
- package/dist/web/assets/railroad-3IZDKUUU-aibJDIDV.js +1 -0
- package/dist/web/assets/railroad-abnf-AHOZXSZD-BBMEuvIl.js +1 -0
- package/dist/web/assets/railroad-ebnf-EBAXGLYW-Be1nseej.js +1 -0
- package/dist/web/assets/railroad-peg-LSFZ7HO6-DIvD-Eyb.js +1 -0
- package/dist/web/assets/railroadDiagram-AXF67PYL-C6-GuR01.js +1 -0
- package/dist/web/assets/{requirementDiagram-LRYGKXZP-D2-9KlK1.js → requirementDiagram-LRYGKXZP-Dew1VZVc.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-W5VNT64P-DSOFAzno.js → sankeyDiagram-W5VNT64P-BNlHXupx.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-SI44F4Z6-BHEKSYJt.js → sequenceDiagram-SI44F4Z6-CHZhbxWH.js} +1 -1
- package/dist/web/assets/stateDiagram-OKZ733FA-BP7TOkRY.js +1 -0
- package/dist/web/assets/stateDiagram-v2-UEYNNEHI-BoFgs-SF.js +1 -0
- package/dist/web/assets/swimlanes-SLNWSIFB-DfMga4nB.js +2 -0
- package/dist/web/assets/swimlanesDiagram-ULZ7WXOC-CpfunQZj.js +8 -0
- package/dist/web/assets/{timeline-definition-Z64GVDOM-C7eeBnPC.js → timeline-definition-Z64GVDOM-DjC-PWK6.js} +1 -1
- package/dist/web/assets/treeView-QDETBFTQ-uHZ-3Fz8.js +1 -0
- package/dist/web/assets/treemap-6X3UGDF4-BnUKyy3l.js +1 -0
- package/dist/web/assets/{vennDiagram-T6HMQDX7-DTIq1ec9.js → vennDiagram-T6HMQDX7-CJzy1Vav.js} +2 -2
- package/dist/web/assets/wardley-OPB4EBWU-Da7TLC2F.js +1 -0
- package/dist/web/assets/{wardleyDiagram-T6FBY63Y-BmzhEoo_.js → wardleyDiagram-T6FBY63Y-C9BlVo6M.js} +3 -3
- package/dist/web/assets/{xychartDiagram-ELKLHX3M-CcCGC0u-.js → xychartDiagram-ELKLHX3M-B0WUxsYy.js} +3 -3
- package/dist/web/index.html +6 -2
- package/package.json +1 -1
- package/skills/rvw-walkthrough/SKILL.md +4 -4
- package/skills/rvw-walkthrough/agents/openai.yaml +1 -1
- package/skills/rvw-walkthrough/references/walkthrough-authoring.md +11 -0
- package/dist/web/assets/DocumentViewer-DtusMl0r.js +0 -1561
- package/dist/web/assets/MarkdownTable-BjwiOHQe.js +0 -15
- package/dist/web/assets/WalkthroughViewer-BNwKsKzk.js +0 -42
- package/dist/web/assets/abnfDiagram-N423BO3Z-DtH8B7Z7.js +0 -1
- package/dist/web/assets/architecture-TIHT7OUA-P_K7H_mW.js +0 -1
- package/dist/web/assets/architectureDiagram-T3A2C74G-5Fq3Xylv.js +0 -36
- package/dist/web/assets/channel-wXu0iczQ.js +0 -1
- package/dist/web/assets/classDiagram-JCYQIIEL-DOHE4q2M.js +0 -1
- package/dist/web/assets/classDiagram-v2-OCEON4UE-DOHE4q2M.js +0 -1
- package/dist/web/assets/cynefin-VYW2F7L2-Dj_jqvQa.js +0 -1
- package/dist/web/assets/cynefinDiagram-MW4NZA55-DSnUS3JS.js +0 -62
- package/dist/web/assets/diagram-B4RE2ZJO-DNtXohxd.js +0 -3
- package/dist/web/assets/diagram-LBJQPF4R-CVD-8DKW.js +0 -24
- package/dist/web/assets/diagram-Q27KOJAE-DBEnUsLJ.js +0 -24
- package/dist/web/assets/diagram-UB23O5K3-DiPHfrk7.js +0 -41
- package/dist/web/assets/ebnfDiagram-BXEA7PRR-CE06v37i.js +0 -1
- package/dist/web/assets/eventmodeling-45OFAUF4-C344zcDl.js +0 -1
- package/dist/web/assets/flowDiagram-UKHOOZJN-BAHsb6fm.js +0 -1
- package/dist/web/assets/gitGraph-TEB2WS4Q-C6oA29oA.js +0 -1
- package/dist/web/assets/gitGraphDiagram-DS77QQ5N-DR1mGQ6a.js +0 -106
- package/dist/web/assets/index-BiPhui1B.js +0 -384
- package/dist/web/assets/index-CHlqmhif.css +0 -1
- package/dist/web/assets/info-DKCQHKI2-BT4oYSnk.js +0 -1
- package/dist/web/assets/infoDiagram-6WML65LV-D0mnXRu0.js +0 -2
- package/dist/web/assets/mermaid-parser.core-BmDn4VB6.js +0 -7
- package/dist/web/assets/mermaid.core-Cus_gjGs.js +0 -42
- package/dist/web/assets/packet-7NZHBO7P-BXuujfeh.js +0 -1
- package/dist/web/assets/pegDiagram-VL7TDLO6-CBF6Uic6.js +0 -1
- package/dist/web/assets/pie-RZYD4A2V-DgssvIaB.js +0 -1
- package/dist/web/assets/pieDiagram-7S7Q4E2Y-DejhR8Wh.js +0 -39
- package/dist/web/assets/radar-I7S5WNFK-CoiIzjHC.js +0 -1
- package/dist/web/assets/railroad-3IZDKUUU-CWq6IkAh.js +0 -1
- package/dist/web/assets/railroad-abnf-AHOZXSZD-D7Iqnp88.js +0 -1
- package/dist/web/assets/railroad-ebnf-EBAXGLYW-Dp2g2TtT.js +0 -1
- package/dist/web/assets/railroad-peg-LSFZ7HO6-DTqKNJKF.js +0 -1
- package/dist/web/assets/railroadDiagram-AXF67PYL-DkePHtcR.js +0 -1
- package/dist/web/assets/stateDiagram-OKZ733FA-f1GttDrB.js +0 -1
- package/dist/web/assets/stateDiagram-v2-UEYNNEHI-CEn2YfQh.js +0 -1
- package/dist/web/assets/swimlanes-SLNWSIFB-Dx7QlDaA.js +0 -2
- package/dist/web/assets/swimlanesDiagram-ULZ7WXOC-CX2pXGLK.js +0 -8
- package/dist/web/assets/treeView-QDETBFTQ-BPsqqMsK.js +0 -1
- package/dist/web/assets/treemap-6X3UGDF4-CmBU76N7.js +0 -1
- package/dist/web/assets/wardley-OPB4EBWU-DLOnGzPl.js +0 -1
package/dist/cli.mjs
CHANGED
|
@@ -7,6 +7,7 @@ var __export = (target, all4) => {
|
|
|
7
7
|
|
|
8
8
|
// src/cli/main.ts
|
|
9
9
|
import { fork } from "node:child_process";
|
|
10
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
10
11
|
import { existsSync as existsSync6 } from "node:fs";
|
|
11
12
|
import path10 from "node:path";
|
|
12
13
|
import { fileURLToPath as fileURLToPath5, pathToFileURL } from "node:url";
|
|
@@ -19093,6 +19094,11 @@ var RvwDatabase = class {
|
|
|
19093
19094
|
listPullRequests() {
|
|
19094
19095
|
return this.database.prepare("SELECT * FROM pull_requests ORDER BY updated_at DESC").all().map(mapPullRequest);
|
|
19095
19096
|
}
|
|
19097
|
+
listPullRequestsNeedingStatusRefresh() {
|
|
19098
|
+
return this.database.prepare(
|
|
19099
|
+
"SELECT * FROM pull_requests WHERE github_state = 'OPEN' OR github_state IS NULL ORDER BY updated_at DESC"
|
|
19100
|
+
).all().map(mapPullRequest);
|
|
19101
|
+
}
|
|
19096
19102
|
listPullRequestSummaries(offset, limit, hideClosedOrMerged = true) {
|
|
19097
19103
|
const hideClosedOrMergedValue = hideClosedOrMerged ? 1 : 0;
|
|
19098
19104
|
const rows = this.database.prepare(
|
|
@@ -19165,6 +19171,25 @@ var RvwDatabase = class {
|
|
|
19165
19171
|
total: numberValue(totalRow, "total")
|
|
19166
19172
|
};
|
|
19167
19173
|
}
|
|
19174
|
+
updatePullRequestGitHubStatuses(updates) {
|
|
19175
|
+
if (updates.length === 0) return;
|
|
19176
|
+
this.immediateTransaction(() => {
|
|
19177
|
+
const statement = this.database.prepare(
|
|
19178
|
+
"UPDATE pull_requests SET github_state = ?, github_is_draft = ? WHERE id = ?"
|
|
19179
|
+
);
|
|
19180
|
+
for (const update of updates) {
|
|
19181
|
+
const result = statement.run(update.state, update.isDraft ? 1 : 0, update.pullRequestId);
|
|
19182
|
+
if (Number(result.changes) !== 1) {
|
|
19183
|
+
throw new RvwError(
|
|
19184
|
+
"PR_NOT_FOUND",
|
|
19185
|
+
`Pull Request\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093: ${update.pullRequestId}`,
|
|
19186
|
+
{ status: 404 }
|
|
19187
|
+
);
|
|
19188
|
+
}
|
|
19189
|
+
}
|
|
19190
|
+
this.incrementChangeSequence();
|
|
19191
|
+
});
|
|
19192
|
+
}
|
|
19168
19193
|
updateRepositoryLocation(id, repository) {
|
|
19169
19194
|
this.immediateTransaction(() => {
|
|
19170
19195
|
const result = this.database.prepare(
|
|
@@ -19870,9 +19895,11 @@ import path5 from "node:path";
|
|
|
19870
19895
|
import { TextDecoder as TextDecoder2 } from "node:util";
|
|
19871
19896
|
|
|
19872
19897
|
// src/shared/constants.ts
|
|
19873
|
-
var APP_VERSION = "0.3.
|
|
19898
|
+
var APP_VERSION = "0.3.2";
|
|
19874
19899
|
var PROTOCOL_VERSION = 4;
|
|
19875
19900
|
var VIEWER_ID_HEADER = "x-rvw-viewer-id";
|
|
19901
|
+
var VIEWER_OPEN_LEASE_HEADER = "x-rvw-viewer-open-lease";
|
|
19902
|
+
var VIEWER_OPEN_LEASE_QUERY = "viewerLease";
|
|
19876
19903
|
var GIT_OBJECT_ID_PATTERN = /^[0-9a-f]{40,64}$/i;
|
|
19877
19904
|
var MAX_TEXT_DOCUMENT_BYTES = 1024 * 1024;
|
|
19878
19905
|
var MAX_MARKDOWN_ASSET_BYTES = 5 * 1024 * 1024;
|
|
@@ -20369,6 +20396,10 @@ var GitClient = class {
|
|
|
20369
20396
|
);
|
|
20370
20397
|
return parseCommitLog(output);
|
|
20371
20398
|
}
|
|
20399
|
+
async firstParent(cwd, oid) {
|
|
20400
|
+
const parents = await runText("git", ["show", "-s", "--format=%P", oid], { cwd });
|
|
20401
|
+
return parents.split(" ").filter(Boolean)[0] ?? null;
|
|
20402
|
+
}
|
|
20372
20403
|
async tree(cwd, oid) {
|
|
20373
20404
|
const result = await runProcess("git", ["ls-tree", "-r", "-z", "--long", oid], { cwd });
|
|
20374
20405
|
return parseLsTree(result.stdout);
|
|
@@ -20381,6 +20412,23 @@ var GitClient = class {
|
|
|
20381
20412
|
);
|
|
20382
20413
|
return parseNameStatus(result.stdout);
|
|
20383
20414
|
}
|
|
20415
|
+
async changedFilesWithCopies(cwd, oldOid, newOid) {
|
|
20416
|
+
const result = await runProcess(
|
|
20417
|
+
"git",
|
|
20418
|
+
[
|
|
20419
|
+
"diff",
|
|
20420
|
+
"--name-status",
|
|
20421
|
+
"-z",
|
|
20422
|
+
"--find-renames",
|
|
20423
|
+
"--find-copies",
|
|
20424
|
+
"--find-copies-harder",
|
|
20425
|
+
oldOid,
|
|
20426
|
+
newOid
|
|
20427
|
+
],
|
|
20428
|
+
{ cwd }
|
|
20429
|
+
);
|
|
20430
|
+
return parseNameStatus(result.stdout);
|
|
20431
|
+
}
|
|
20384
20432
|
async readDocument(cwd, sourceOid, filePath) {
|
|
20385
20433
|
assertGitPath(filePath);
|
|
20386
20434
|
const result = await runProcess("git", ["ls-tree", "-z", "--long", sourceOid, "--", filePath], {
|
|
@@ -20643,6 +20691,10 @@ var ghPullRequestSchema = external_exports.object({
|
|
|
20643
20691
|
headRefOid: external_exports.string().regex(GIT_OBJECT_ID_PATTERN),
|
|
20644
20692
|
createdAt: external_exports.string()
|
|
20645
20693
|
});
|
|
20694
|
+
var ghPullRequestStatusSchema = external_exports.object({
|
|
20695
|
+
state: external_exports.enum(["OPEN", "CLOSED", "MERGED"]),
|
|
20696
|
+
isDraft: external_exports.boolean()
|
|
20697
|
+
});
|
|
20646
20698
|
function parsePullRequestUrl(url2) {
|
|
20647
20699
|
const match2 = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)(?:\/.*)?$/.exec(url2);
|
|
20648
20700
|
if (!match2?.[1] || !match2[2] || !match2[3]) {
|
|
@@ -20663,7 +20715,7 @@ var GitHubClient = class {
|
|
|
20663
20715
|
return { version: version2.split("\n")[0] ?? version2, authenticated: auth.exitCode === 0 };
|
|
20664
20716
|
}
|
|
20665
20717
|
async assertAuthenticated() {
|
|
20666
|
-
const status = await
|
|
20718
|
+
const status = await this.processRunner("gh", ["auth", "status", "--hostname", "github.com"], {
|
|
20667
20719
|
allowExitCodes: [1]
|
|
20668
20720
|
});
|
|
20669
20721
|
if (status.exitCode !== 0) {
|
|
@@ -20672,6 +20724,77 @@ var GitHubClient = class {
|
|
|
20672
20724
|
});
|
|
20673
20725
|
}
|
|
20674
20726
|
}
|
|
20727
|
+
async getPullRequestStatus(reference) {
|
|
20728
|
+
let output;
|
|
20729
|
+
try {
|
|
20730
|
+
const result = await this.processRunner(
|
|
20731
|
+
"gh",
|
|
20732
|
+
["pr", "view", reference, "--json", "state,isDraft"],
|
|
20733
|
+
{ timeoutMs: 6e4 }
|
|
20734
|
+
);
|
|
20735
|
+
output = result.stdout.toString("utf8").trimEnd();
|
|
20736
|
+
} catch (error51) {
|
|
20737
|
+
if (error51 instanceof RvwError && error51.code === "PROCESS_FAILED") {
|
|
20738
|
+
throw new RvwError("GITHUB_ERROR", "Pull Request\u72B6\u614B\u3092GitHub\u304B\u3089\u53D6\u5F97\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002", {
|
|
20739
|
+
cause: error51,
|
|
20740
|
+
details: error51.details,
|
|
20741
|
+
suggestions: ["PR URL\u3068gh\u8A8D\u8A3C\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002"]
|
|
20742
|
+
});
|
|
20743
|
+
}
|
|
20744
|
+
throw error51;
|
|
20745
|
+
}
|
|
20746
|
+
let decoded;
|
|
20747
|
+
try {
|
|
20748
|
+
decoded = JSON.parse(output);
|
|
20749
|
+
} catch (error51) {
|
|
20750
|
+
throw new RvwError("GITHUB_ERROR", "GitHub CLI\u306EPull Request\u72B6\u614B\u5FDC\u7B54\u304C\u4E0D\u6B63\u3067\u3059\u3002", {
|
|
20751
|
+
cause: error51
|
|
20752
|
+
});
|
|
20753
|
+
}
|
|
20754
|
+
const parsed = ghPullRequestStatusSchema.safeParse(decoded);
|
|
20755
|
+
if (!parsed.success) {
|
|
20756
|
+
throw new RvwError("GITHUB_ERROR", "GitHub CLI\u306EPull Request\u72B6\u614B\u5FDC\u7B54\u304C\u4E0D\u6B63\u3067\u3059\u3002", {
|
|
20757
|
+
details: parsed.error.flatten()
|
|
20758
|
+
});
|
|
20759
|
+
}
|
|
20760
|
+
return parsed.data;
|
|
20761
|
+
}
|
|
20762
|
+
async getPullRequestStatuses(references) {
|
|
20763
|
+
if (references.length === 0) return [];
|
|
20764
|
+
await this.assertAuthenticated();
|
|
20765
|
+
const outcomes = Array.from(
|
|
20766
|
+
{ length: references.length },
|
|
20767
|
+
() => void 0
|
|
20768
|
+
);
|
|
20769
|
+
let nextIndex = 0;
|
|
20770
|
+
const workerCount = Math.min(4, references.length);
|
|
20771
|
+
await Promise.all(
|
|
20772
|
+
Array.from({ length: workerCount }, async () => {
|
|
20773
|
+
while (nextIndex < references.length) {
|
|
20774
|
+
const index2 = nextIndex;
|
|
20775
|
+
nextIndex += 1;
|
|
20776
|
+
const reference = references[index2];
|
|
20777
|
+
if (!reference) continue;
|
|
20778
|
+
try {
|
|
20779
|
+
outcomes[index2] = {
|
|
20780
|
+
status: "fulfilled",
|
|
20781
|
+
value: await this.getPullRequestStatus(reference)
|
|
20782
|
+
};
|
|
20783
|
+
} catch (error51) {
|
|
20784
|
+
outcomes[index2] = { status: "rejected", error: error51 };
|
|
20785
|
+
}
|
|
20786
|
+
}
|
|
20787
|
+
})
|
|
20788
|
+
);
|
|
20789
|
+
return outcomes.map((outcome) => {
|
|
20790
|
+
if (!outcome) {
|
|
20791
|
+
throw new RvwError("INTERNAL_ERROR", "Pull Request\u72B6\u614B\u306E\u4E00\u62EC\u53D6\u5F97\u7D50\u679C\u304C\u4E0D\u8DB3\u3057\u3066\u3044\u307E\u3059\u3002", {
|
|
20792
|
+
status: 500
|
|
20793
|
+
});
|
|
20794
|
+
}
|
|
20795
|
+
return outcome;
|
|
20796
|
+
});
|
|
20797
|
+
}
|
|
20675
20798
|
async getPullRequest(reference, cwd, options = {}) {
|
|
20676
20799
|
await this.assertAuthenticated();
|
|
20677
20800
|
const fields = [
|
|
@@ -27969,11 +28092,22 @@ function selectedLineText(value, startLine, endLine) {
|
|
|
27969
28092
|
function lines(text5) {
|
|
27970
28093
|
return normalizeLf(text5).split("\n");
|
|
27971
28094
|
}
|
|
28095
|
+
function countLineRangeOccurrences(documentLines, selected) {
|
|
28096
|
+
let occurrences = 0;
|
|
28097
|
+
for (let index2 = 0; index2 <= documentLines.length - selected.length; index2 += 1) {
|
|
28098
|
+
if (selected.every((line, offset) => documentLines[index2 + offset] === line)) {
|
|
28099
|
+
occurrences += 1;
|
|
28100
|
+
}
|
|
28101
|
+
}
|
|
28102
|
+
return occurrences;
|
|
28103
|
+
}
|
|
27972
28104
|
function mapUnchangedLineRange(sourceText, destinationText, startLine, endLine) {
|
|
27973
28105
|
if (startLine < 1 || endLine < startLine) return null;
|
|
27974
28106
|
const sourceLines = lines(sourceText);
|
|
27975
28107
|
if (endLine > sourceLines.length) return null;
|
|
27976
28108
|
if (sourceText === destinationText) return { startLine, endLine };
|
|
28109
|
+
const selected = sourceLines.slice(startLine - 1, endLine);
|
|
28110
|
+
if (countLineRangeOccurrences(sourceLines, selected) !== 1) return null;
|
|
27977
28111
|
const mapping = /* @__PURE__ */ new Map();
|
|
27978
28112
|
let sourceIndex = 1;
|
|
27979
28113
|
let destinationIndex = 1;
|
|
@@ -27999,14 +28133,8 @@ function mapUnchangedLineRange(sourceText, destinationText, startLine, endLine)
|
|
|
27999
28133
|
for (let line = startLine; line <= endLine; line += 1) {
|
|
28000
28134
|
if (mapping.get(line) !== mappedStart + line - startLine) return null;
|
|
28001
28135
|
}
|
|
28002
|
-
const selected = sourceLines.slice(startLine - 1, endLine);
|
|
28003
|
-
let occurrences = 0;
|
|
28004
28136
|
const destinationLines = lines(destinationText);
|
|
28005
|
-
|
|
28006
|
-
if (selected.every((line, offset) => destinationLines[index2 + offset] === line))
|
|
28007
|
-
occurrences += 1;
|
|
28008
|
-
if (occurrences > 1) return null;
|
|
28009
|
-
}
|
|
28137
|
+
if (countLineRangeOccurrences(destinationLines, selected) !== 1) return null;
|
|
28010
28138
|
return { startLine: mappedStart, endLine: mappedEnd };
|
|
28011
28139
|
}
|
|
28012
28140
|
function findUniqueQuotedLineRange(quotedText, destinationText) {
|
|
@@ -28034,6 +28162,11 @@ function placeMutableDocumentComment(anchor, currentText) {
|
|
|
28034
28162
|
return range ? { outdated: false, range } : { outdated: true, range: null };
|
|
28035
28163
|
}
|
|
28036
28164
|
|
|
28165
|
+
// src/domain/walkthrough-reference.ts
|
|
28166
|
+
function walkthroughReferenceFingerprint(sourceOid, reference) {
|
|
28167
|
+
return JSON.stringify([sourceOid, reference.path, reference.startLine, reference.endLine]);
|
|
28168
|
+
}
|
|
28169
|
+
|
|
28037
28170
|
// src/domain/source-excerpt.ts
|
|
28038
28171
|
var SOURCE_EXCERPT_CONTEXT_LINES = 20;
|
|
28039
28172
|
var MAX_SOURCE_EXCERPT_LINES = 200;
|
|
@@ -41003,7 +41136,8 @@ var codeReferenceIdPattern = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/;
|
|
|
41003
41136
|
var walkthroughDiagramNodePattern = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/;
|
|
41004
41137
|
var mermaidIdentifierPattern = /[A-Za-z][A-Za-z0-9_-]{0,63}/g;
|
|
41005
41138
|
var mermaidEdgePattern = /[<|o*x]*[-.=~]{2,}[|o*x>]*/g;
|
|
41006
|
-
var
|
|
41139
|
+
var mermaidClassShorthandPattern = /:::[A-Za-z][A-Za-z0-9_-]*(?:,[A-Za-z][A-Za-z0-9_-]*)*/g;
|
|
41140
|
+
var flowchartAndClassKeywords = /* @__PURE__ */ new Set([
|
|
41007
41141
|
"class",
|
|
41008
41142
|
"classDef",
|
|
41009
41143
|
"classDiagram",
|
|
@@ -41015,12 +41149,19 @@ var mermaidKeywords = /* @__PURE__ */ new Set([
|
|
|
41015
41149
|
"style",
|
|
41016
41150
|
"subgraph"
|
|
41017
41151
|
]);
|
|
41018
|
-
|
|
41019
|
-
|
|
41152
|
+
var noMermaidKeywords = /* @__PURE__ */ new Set();
|
|
41153
|
+
function mermaidIdentifiers(value, excludedKeywords) {
|
|
41154
|
+
return [...value.matchAll(mermaidIdentifierPattern)].map(([identifier]) => identifier).filter((identifier) => !excludedKeywords.has(identifier));
|
|
41020
41155
|
}
|
|
41021
|
-
function
|
|
41156
|
+
function mermaidLineWithoutComment(value) {
|
|
41022
41157
|
const commentIndex = value.indexOf("%%");
|
|
41023
|
-
|
|
41158
|
+
return commentIndex === -1 ? value : value.slice(0, commentIndex);
|
|
41159
|
+
}
|
|
41160
|
+
function mermaidLineWithoutClassShorthand(value) {
|
|
41161
|
+
return value.replace(mermaidClassShorthandPattern, "");
|
|
41162
|
+
}
|
|
41163
|
+
function mermaidLineWithoutLabels(value) {
|
|
41164
|
+
const uncommented = mermaidLineWithoutComment(value);
|
|
41024
41165
|
const withoutQuotedLabels = uncommented.replace(/"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'/g, " ").replace(/\|[^|]*\|/g, " ").replace(/--\s+[^-\n]+\s+-->/g, " -->").replace(/-\.\s+[^.\n]+\s+\.->/g, " -.->").replace(/==\s+[^=\n]+\s+==>/g, " ==>");
|
|
41025
41166
|
let result = "";
|
|
41026
41167
|
const closingDelimiters = [];
|
|
@@ -41045,33 +41186,105 @@ function mermaidLineWithoutLabels(value) {
|
|
|
41045
41186
|
}
|
|
41046
41187
|
return result;
|
|
41047
41188
|
}
|
|
41048
|
-
function addMermaidEdgeEndpoints(line, nodeIds) {
|
|
41049
|
-
const
|
|
41189
|
+
function addMermaidEdgeEndpoints(line, nodeIds, excludedKeywords) {
|
|
41190
|
+
const endpointLine = mermaidLineWithoutClassShorthand(line);
|
|
41191
|
+
const edges = [...endpointLine.matchAll(mermaidEdgePattern)];
|
|
41050
41192
|
for (let index2 = 0; index2 < edges.length; index2 += 1) {
|
|
41051
41193
|
const edge = edges[index2];
|
|
41052
41194
|
const edgeStart = edge.index;
|
|
41053
41195
|
const edgeEnd = edgeStart + edge[0].length;
|
|
41054
41196
|
const leftStart = index2 === 0 ? 0 : edges[index2 - 1].index + edges[index2 - 1][0].length;
|
|
41055
|
-
const rightEnd = index2 + 1 === edges.length ?
|
|
41056
|
-
const left =
|
|
41057
|
-
const right =
|
|
41058
|
-
const leftIdentifiers = mermaidIdentifiers(left);
|
|
41059
|
-
const rightIdentifiers = mermaidIdentifiers(right);
|
|
41197
|
+
const rightEnd = index2 + 1 === edges.length ? endpointLine.length : edges[index2 + 1].index;
|
|
41198
|
+
const left = endpointLine.slice(leftStart, edgeStart);
|
|
41199
|
+
const right = endpointLine.slice(edgeEnd, rightEnd);
|
|
41200
|
+
const leftIdentifiers = mermaidIdentifiers(left, excludedKeywords);
|
|
41201
|
+
const rightIdentifiers = mermaidIdentifiers(right, excludedKeywords);
|
|
41060
41202
|
const leftEndpoints = left.includes("&") ? leftIdentifiers : leftIdentifiers.slice(-1);
|
|
41061
41203
|
const rightEndpoints = right.includes("&") ? rightIdentifiers : rightIdentifiers.slice(0, 1);
|
|
41062
41204
|
for (const identifier of [...leftEndpoints, ...rightEndpoints]) nodeIds.add(identifier);
|
|
41063
41205
|
}
|
|
41064
41206
|
}
|
|
41207
|
+
function addSequenceMessageParticipants(line, nodeIds) {
|
|
41208
|
+
const message = line.match(
|
|
41209
|
+
/^([A-Za-z][A-Za-z0-9_-]{0,63})\s*<*[-=]+[)>x]+\s*[+-]?([A-Za-z][A-Za-z0-9_-]{0,63})\b/
|
|
41210
|
+
);
|
|
41211
|
+
if (!message) return;
|
|
41212
|
+
nodeIds.add(message[1]);
|
|
41213
|
+
nodeIds.add(message[2]);
|
|
41214
|
+
}
|
|
41215
|
+
var erCardinalitySource = [
|
|
41216
|
+
"one\\s+or\\s+zero",
|
|
41217
|
+
"one\\s+or\\s+(?:more|many)",
|
|
41218
|
+
"zero\\s+or\\s+(?:one|more|many)",
|
|
41219
|
+
"only\\s+one",
|
|
41220
|
+
"many\\([01]\\)",
|
|
41221
|
+
"[01]\\+",
|
|
41222
|
+
"many",
|
|
41223
|
+
"one",
|
|
41224
|
+
"\\d+(?:\\.\\d+)?"
|
|
41225
|
+
].join("|");
|
|
41226
|
+
var erTextualRelationshipPattern = new RegExp(
|
|
41227
|
+
`^([A-Za-z][A-Za-z0-9_-]{0,63})\\s+(?:${erCardinalitySource})\\s+(?:to|optionally\\s+to)\\s+(?:${erCardinalitySource})\\s+([A-Za-z][A-Za-z0-9_-]{0,63})\\b`,
|
|
41228
|
+
"i"
|
|
41229
|
+
);
|
|
41230
|
+
function addErRelationshipEntities(line, nodeIds) {
|
|
41231
|
+
const relationship = line.match(
|
|
41232
|
+
/^([A-Za-z][A-Za-z0-9_-]{0,63})\s+[|o}{]+[.-]{2}[|o}{]+\s+([A-Za-z][A-Za-z0-9_-]{0,63})\b/
|
|
41233
|
+
) ?? line.match(erTextualRelationshipPattern);
|
|
41234
|
+
if (!relationship) return;
|
|
41235
|
+
nodeIds.add(relationship[1]);
|
|
41236
|
+
nodeIds.add(relationship[2]);
|
|
41237
|
+
}
|
|
41065
41238
|
function addMermaidDiagramNodes(source, nodeIds) {
|
|
41066
41239
|
const lines2 = source.split("\n");
|
|
41067
41240
|
const header = lines2.map((line) => mermaidLineWithoutLabels(line).trim()).find((line) => line.length > 0);
|
|
41068
|
-
const diagramType = header?.match(
|
|
41241
|
+
const diagramType = header?.match(
|
|
41242
|
+
/^(flowchart|graph|classDiagram|sequenceDiagram|stateDiagram-v2|erDiagram|architecture-beta)\b/
|
|
41243
|
+
)?.[1];
|
|
41069
41244
|
if (!diagramType) return;
|
|
41070
41245
|
for (const rawLine of lines2) {
|
|
41071
|
-
|
|
41246
|
+
const diagramLine = diagramType === "erDiagram" || diagramType === "sequenceDiagram" ? mermaidLineWithoutComment(rawLine) : mermaidLineWithoutLabels(rawLine);
|
|
41247
|
+
for (const statement of diagramLine.split(";")) {
|
|
41072
41248
|
const line = statement.trim();
|
|
41073
|
-
if (!line || /^(flowchart|graph|classDiagram)\b/.test(
|
|
41074
|
-
|
|
41249
|
+
if (!line || /^(flowchart|graph|classDiagram|sequenceDiagram|stateDiagram-v2|erDiagram|architecture-beta)\b/.test(
|
|
41250
|
+
line
|
|
41251
|
+
)) {
|
|
41252
|
+
continue;
|
|
41253
|
+
}
|
|
41254
|
+
if (diagramType === "sequenceDiagram") {
|
|
41255
|
+
const participant = line.match(
|
|
41256
|
+
/^(?:participant|actor)\s+([A-Za-z][A-Za-z0-9_-]{0,63})(?:\s*@\s*\{|\s+as\b|\s*$)/
|
|
41257
|
+
)?.[1];
|
|
41258
|
+
if (participant) nodeIds.add(participant);
|
|
41259
|
+
else addSequenceMessageParticipants(line, nodeIds);
|
|
41260
|
+
continue;
|
|
41261
|
+
}
|
|
41262
|
+
if (diagramType === "architecture-beta") {
|
|
41263
|
+
const service = line.match(/^service\s+([A-Za-z][A-Za-z0-9_-]{0,63})(?:\s|\(|$)/)?.[1];
|
|
41264
|
+
if (service) nodeIds.add(service);
|
|
41265
|
+
continue;
|
|
41266
|
+
}
|
|
41267
|
+
if (diagramType === "stateDiagram-v2") {
|
|
41268
|
+
addMermaidEdgeEndpoints(line, nodeIds, noMermaidKeywords);
|
|
41269
|
+
const alias = line.match(/^state\s+.+?\s+as\s+([A-Za-z][A-Za-z0-9_-]{0,63})\b/)?.[1];
|
|
41270
|
+
const declaration = alias ? void 0 : line.match(/^state\s+([A-Za-z][A-Za-z0-9_-]{0,63})(?:\s|\{|$)/)?.[1];
|
|
41271
|
+
const describedState = line.match(/^([A-Za-z][A-Za-z0-9_-]{0,63})\s*:/)?.[1];
|
|
41272
|
+
const standaloneState = line.match(/^([A-Za-z][A-Za-z0-9_-]{0,63})$/)?.[1];
|
|
41273
|
+
for (const identifier of [alias, declaration, describedState, standaloneState]) {
|
|
41274
|
+
if (identifier) nodeIds.add(identifier);
|
|
41275
|
+
}
|
|
41276
|
+
continue;
|
|
41277
|
+
}
|
|
41278
|
+
if (diagramType === "erDiagram") {
|
|
41279
|
+
const entityLine = mermaidLineWithoutClassShorthand(line);
|
|
41280
|
+
addErRelationshipEntities(entityLine, nodeIds);
|
|
41281
|
+
const entity = entityLine.match(
|
|
41282
|
+
/^([A-Za-z][A-Za-z0-9_-]{0,63})(?:\s*\[[^\]\n]+\])?\s*(?:\{|$)/
|
|
41283
|
+
)?.[1];
|
|
41284
|
+
if (entity) nodeIds.add(entity);
|
|
41285
|
+
continue;
|
|
41286
|
+
}
|
|
41287
|
+
addMermaidEdgeEndpoints(line, nodeIds, flowchartAndClassKeywords);
|
|
41075
41288
|
if (diagramType === "classDiagram") {
|
|
41076
41289
|
const declaration = line.match(/^class\s+([A-Za-z][A-Za-z0-9_-]{0,63})\b/)?.[1];
|
|
41077
41290
|
const memberOwner = line.match(/^([A-Za-z][A-Za-z0-9_-]{0,63})\s*:/)?.[1];
|
|
@@ -41282,6 +41495,42 @@ var RvwService = class {
|
|
|
41282
41495
|
}
|
|
41283
41496
|
};
|
|
41284
41497
|
}
|
|
41498
|
+
async refreshPullRequestStatuses() {
|
|
41499
|
+
const pullRequests = this.database.listPullRequestsNeedingStatusRefresh();
|
|
41500
|
+
if (pullRequests.length === 0) {
|
|
41501
|
+
return { attempted: 0, updated: 0, failures: [] };
|
|
41502
|
+
}
|
|
41503
|
+
const outcomes = await this.github.getPullRequestStatuses(
|
|
41504
|
+
pullRequests.map((pullRequest) => pullRequest.url)
|
|
41505
|
+
);
|
|
41506
|
+
if (outcomes.length !== pullRequests.length) {
|
|
41507
|
+
throw new RvwError("GITHUB_ERROR", "Pull Request\u72B6\u614B\u306E\u4E00\u62EC\u53D6\u5F97\u4EF6\u6570\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002", {
|
|
41508
|
+
status: 502
|
|
41509
|
+
});
|
|
41510
|
+
}
|
|
41511
|
+
const successful = outcomes.flatMap((outcome, index2) => {
|
|
41512
|
+
const pullRequest = pullRequests[index2];
|
|
41513
|
+
return outcome.status === "fulfilled" && pullRequest ? [{ pullRequestId: pullRequest.id, ...outcome.value }] : [];
|
|
41514
|
+
});
|
|
41515
|
+
this.database.updatePullRequestGitHubStatuses(successful);
|
|
41516
|
+
const failures = outcomes.flatMap((outcome, index2) => {
|
|
41517
|
+
const pullRequest = pullRequests[index2];
|
|
41518
|
+
return outcome.status === "rejected" && pullRequest ? [
|
|
41519
|
+
{
|
|
41520
|
+
pullRequestId: pullRequest.id,
|
|
41521
|
+
owner: pullRequest.owner,
|
|
41522
|
+
repository: pullRequest.repository,
|
|
41523
|
+
number: pullRequest.number,
|
|
41524
|
+
error: asRvwError(outcome.error).toJSON()
|
|
41525
|
+
}
|
|
41526
|
+
] : [];
|
|
41527
|
+
});
|
|
41528
|
+
return {
|
|
41529
|
+
attempted: pullRequests.length,
|
|
41530
|
+
updated: successful.length,
|
|
41531
|
+
failures
|
|
41532
|
+
};
|
|
41533
|
+
}
|
|
41285
41534
|
resolveStoredPullRequest(reference) {
|
|
41286
41535
|
if (/^https:\/\/github\.com\//.test(reference)) {
|
|
41287
41536
|
const parsed = parsePullRequestUrl(reference);
|
|
@@ -41953,6 +42202,133 @@ var RvwService = class {
|
|
|
41953
42202
|
}
|
|
41954
42203
|
return walkthrough;
|
|
41955
42204
|
}
|
|
42205
|
+
async walkthroughReferenceFallbackTarget(pullRequest, sourceOid, filePath) {
|
|
42206
|
+
const diffBaseOid = await this.git.firstParent(pullRequest.localRepositoryPath, sourceOid);
|
|
42207
|
+
if (!diffBaseOid) {
|
|
42208
|
+
return {
|
|
42209
|
+
sourceOid,
|
|
42210
|
+
path: filePath,
|
|
42211
|
+
diffBaseOid: null,
|
|
42212
|
+
oldPath: filePath,
|
|
42213
|
+
newPath: filePath,
|
|
42214
|
+
hasDiff: false
|
|
42215
|
+
};
|
|
42216
|
+
}
|
|
42217
|
+
const change = (await this.git.changedFiles(pullRequest.localRepositoryPath, diffBaseOid, sourceOid)).find((candidate) => candidate.newPath === filePath);
|
|
42218
|
+
return {
|
|
42219
|
+
sourceOid,
|
|
42220
|
+
path: filePath,
|
|
42221
|
+
diffBaseOid,
|
|
42222
|
+
oldPath: change?.oldPath ?? filePath,
|
|
42223
|
+
newPath: change?.newPath ?? filePath,
|
|
42224
|
+
hasDiff: change !== void 0
|
|
42225
|
+
};
|
|
42226
|
+
}
|
|
42227
|
+
async resolveWalkthroughReference(pullRequestId, walkthroughId, referenceId) {
|
|
42228
|
+
const pullRequest = this.getPullRequest(pullRequestId);
|
|
42229
|
+
const walkthrough = this.getWalkthrough(pullRequestId, walkthroughId);
|
|
42230
|
+
const reference = walkthrough.references.find((candidate) => candidate.id === referenceId);
|
|
42231
|
+
if (!reference) {
|
|
42232
|
+
throw new RvwError("NOT_FOUND", "Walkthrough\u306Ecode reference\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002", {
|
|
42233
|
+
status: 404
|
|
42234
|
+
});
|
|
42235
|
+
}
|
|
42236
|
+
const referenceFingerprint = walkthroughReferenceFingerprint(walkthrough.sourceOid, reference);
|
|
42237
|
+
const sourceDocument = await this.getDocument({
|
|
42238
|
+
kind: "repository-file",
|
|
42239
|
+
pullRequestId,
|
|
42240
|
+
sourceOid: walkthrough.sourceOid,
|
|
42241
|
+
path: reference.path
|
|
42242
|
+
});
|
|
42243
|
+
const latestHeadOid = pullRequest.latestHeadOid;
|
|
42244
|
+
let latestPath = reference.path;
|
|
42245
|
+
let latestDocument;
|
|
42246
|
+
if (walkthrough.sourceOid === latestHeadOid) {
|
|
42247
|
+
latestDocument = sourceDocument;
|
|
42248
|
+
} else {
|
|
42249
|
+
latestDocument = await this.getDocument({
|
|
42250
|
+
kind: "repository-file",
|
|
42251
|
+
pullRequestId,
|
|
42252
|
+
sourceOid: latestHeadOid,
|
|
42253
|
+
path: reference.path
|
|
42254
|
+
});
|
|
42255
|
+
if (latestDocument.availability === "missing") {
|
|
42256
|
+
const successorPaths = [
|
|
42257
|
+
...new Set(
|
|
42258
|
+
(await this.git.changedFilesWithCopies(
|
|
42259
|
+
pullRequest.localRepositoryPath,
|
|
42260
|
+
walkthrough.sourceOid,
|
|
42261
|
+
latestHeadOid
|
|
42262
|
+
)).filter(
|
|
42263
|
+
(candidate) => (candidate.status.startsWith("R") || candidate.status.startsWith("C")) && candidate.oldPath === reference.path && candidate.newPath !== null
|
|
42264
|
+
).map((candidate) => candidate.newPath)
|
|
42265
|
+
)
|
|
42266
|
+
];
|
|
42267
|
+
latestPath = successorPaths.length === 1 ? successorPaths[0] : null;
|
|
42268
|
+
latestDocument = latestPath === null ? null : await this.getDocument({
|
|
42269
|
+
kind: "repository-file",
|
|
42270
|
+
pullRequestId,
|
|
42271
|
+
sourceOid: latestHeadOid,
|
|
42272
|
+
path: latestPath
|
|
42273
|
+
});
|
|
42274
|
+
}
|
|
42275
|
+
}
|
|
42276
|
+
const latestFileExists = latestDocument !== null && latestDocument.availability !== "missing";
|
|
42277
|
+
const latestFileDisplayable = latestDocument?.availability === "available";
|
|
42278
|
+
const mappedRange = reference.startLine === null || reference.endLine === null ? latestFileDisplayable ? null : void 0 : sourceDocument.availability === "available" && latestDocument?.availability === "available" ? mapUnchangedLineRange(
|
|
42279
|
+
sourceDocument.text ?? "",
|
|
42280
|
+
latestDocument.text ?? "",
|
|
42281
|
+
reference.startLine,
|
|
42282
|
+
reference.endLine
|
|
42283
|
+
) : null;
|
|
42284
|
+
const resolvedToLatest = latestFileDisplayable && (reference.startLine === null || reference.endLine === null || mappedRange !== null);
|
|
42285
|
+
if (resolvedToLatest && latestPath !== null && latestDocument !== null) {
|
|
42286
|
+
return {
|
|
42287
|
+
outcome: "latest",
|
|
42288
|
+
anchorSourceOid: walkthrough.sourceOid,
|
|
42289
|
+
latestHeadOid,
|
|
42290
|
+
referenceFingerprint,
|
|
42291
|
+
target: {
|
|
42292
|
+
sourceOid: latestHeadOid,
|
|
42293
|
+
path: latestPath,
|
|
42294
|
+
diffBaseOid: null,
|
|
42295
|
+
oldPath: latestPath,
|
|
42296
|
+
newPath: latestPath,
|
|
42297
|
+
hasDiff: false,
|
|
42298
|
+
startLine: mappedRange?.startLine ?? reference.startLine,
|
|
42299
|
+
endLine: mappedRange?.endLine ?? reference.endLine
|
|
42300
|
+
},
|
|
42301
|
+
latestFile: null,
|
|
42302
|
+
document: latestDocument
|
|
42303
|
+
};
|
|
42304
|
+
}
|
|
42305
|
+
const targetFile = await this.walkthroughReferenceFallbackTarget(
|
|
42306
|
+
pullRequest,
|
|
42307
|
+
walkthrough.sourceOid,
|
|
42308
|
+
reference.path
|
|
42309
|
+
);
|
|
42310
|
+
const latestFile = latestFileExists && latestPath !== null ? {
|
|
42311
|
+
sourceOid: latestHeadOid,
|
|
42312
|
+
path: latestPath,
|
|
42313
|
+
diffBaseOid: null,
|
|
42314
|
+
oldPath: latestPath,
|
|
42315
|
+
newPath: latestPath,
|
|
42316
|
+
hasDiff: false
|
|
42317
|
+
} : null;
|
|
42318
|
+
return {
|
|
42319
|
+
outcome: "source-fallback",
|
|
42320
|
+
anchorSourceOid: walkthrough.sourceOid,
|
|
42321
|
+
latestHeadOid,
|
|
42322
|
+
referenceFingerprint,
|
|
42323
|
+
target: {
|
|
42324
|
+
...targetFile,
|
|
42325
|
+
startLine: reference.startLine,
|
|
42326
|
+
endLine: reference.endLine
|
|
42327
|
+
},
|
|
42328
|
+
latestFile,
|
|
42329
|
+
document: sourceDocument
|
|
42330
|
+
};
|
|
42331
|
+
}
|
|
41956
42332
|
getWalkthroughByUri(uri) {
|
|
41957
42333
|
const walkthrough = this.database.getWalkthrough(parseWalkthroughUri(uri));
|
|
41958
42334
|
if (!walkthrough) {
|
|
@@ -42001,7 +42377,7 @@ var RvwService = class {
|
|
|
42001
42377
|
if (!markdown.mermaidNodeIds.has(nodeId)) {
|
|
42002
42378
|
throw new RvwError(
|
|
42003
42379
|
"INVALID_INPUT",
|
|
42004
|
-
`Mermaid
|
|
42380
|
+
`Mermaid binding\u5BFE\u8C61\u304C\u672C\u6587\u306E\u5BFE\u5FDCdiagram\u306B\u898B\u3064\u304B\u308A\u307E\u305B\u3093: ${nodeId}`
|
|
42005
42381
|
);
|
|
42006
42382
|
}
|
|
42007
42383
|
}
|
|
@@ -42639,6 +43015,9 @@ var SkillInstaller = class {
|
|
|
42639
43015
|
}
|
|
42640
43016
|
};
|
|
42641
43017
|
|
|
43018
|
+
// src/server/start-server.ts
|
|
43019
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
43020
|
+
|
|
42642
43021
|
// node_modules/.pnpm/@hono+node-server@2.1.0_hono@4.13.1/node_modules/@hono/node-server/dist/constants-BLSFu_RU.mjs
|
|
42643
43022
|
var X_ALREADY_SENT = "x-hono-already-sent";
|
|
42644
43023
|
|
|
@@ -46532,7 +46911,11 @@ function createApp(service, options) {
|
|
|
46532
46911
|
app.get("/api/meta/change-sequence", (context) => {
|
|
46533
46912
|
const rawViewerId = context.req.header(VIEWER_ID_HEADER);
|
|
46534
46913
|
if (rawViewerId !== void 0) {
|
|
46535
|
-
|
|
46914
|
+
const rawViewerLease = context.req.header(VIEWER_OPEN_LEASE_HEADER);
|
|
46915
|
+
options.viewerLifecycle?.heartbeat(
|
|
46916
|
+
viewerIdSchema.parse(rawViewerId),
|
|
46917
|
+
rawViewerLease === void 0 ? void 0 : viewerIdSchema.parse(rawViewerLease)
|
|
46918
|
+
);
|
|
46536
46919
|
}
|
|
46537
46920
|
return context.json({ ok: true, changeSequence: service.database.getChangeSequence() });
|
|
46538
46921
|
});
|
|
@@ -46560,6 +46943,10 @@ function createApp(service, options) {
|
|
|
46560
46943
|
});
|
|
46561
46944
|
return context.json({ ok: true, ...service.listPullRequests(query) });
|
|
46562
46945
|
});
|
|
46946
|
+
app.post(
|
|
46947
|
+
"/api/pull-requests/refresh-statuses",
|
|
46948
|
+
async (context) => context.json({ ok: true, ...await service.refreshPullRequestStatuses() })
|
|
46949
|
+
);
|
|
46563
46950
|
app.get(
|
|
46564
46951
|
"/api/pull-requests/:id",
|
|
46565
46952
|
async (context) => context.json({ ok: true, ...await service.getPullRequestView(context.req.param("id")) })
|
|
@@ -46691,6 +47078,17 @@ function createApp(service, options) {
|
|
|
46691
47078
|
walkthroughs: service.listWalkthroughs(context.req.param("id"))
|
|
46692
47079
|
})
|
|
46693
47080
|
);
|
|
47081
|
+
app.get(
|
|
47082
|
+
"/api/pull-requests/:id/walkthroughs/:walkthroughId/references/:referenceId/resolve",
|
|
47083
|
+
async (context) => context.json({
|
|
47084
|
+
ok: true,
|
|
47085
|
+
resolution: await service.resolveWalkthroughReference(
|
|
47086
|
+
context.req.param("id"),
|
|
47087
|
+
context.req.param("walkthroughId"),
|
|
47088
|
+
context.req.param("referenceId")
|
|
47089
|
+
)
|
|
47090
|
+
})
|
|
47091
|
+
);
|
|
46694
47092
|
app.get(
|
|
46695
47093
|
"/api/pull-requests/:id/walkthroughs/:walkthroughId",
|
|
46696
47094
|
(context) => context.json({
|
|
@@ -46837,14 +47235,17 @@ var ViewerLifecycle = class {
|
|
|
46837
47235
|
constructor(options) {
|
|
46838
47236
|
this.options = options;
|
|
46839
47237
|
this.leaseTimeoutMs = options.leaseTimeoutMs ?? DEFAULT_VIEWER_LEASE_TIMEOUT_MS;
|
|
47238
|
+
this.startupTimeoutMs = options.startupTimeoutMs ?? DEFAULT_VIEWER_STARTUP_TIMEOUT_MS;
|
|
46840
47239
|
this.closeGraceMs = options.closeGraceMs ?? DEFAULT_VIEWER_CLOSE_GRACE_MS;
|
|
46841
47240
|
this.timerLatenessToleranceMs = options.timerLatenessToleranceMs ?? DEFAULT_TIMER_LATENESS_TOLERANCE_MS;
|
|
46842
47241
|
}
|
|
46843
47242
|
options;
|
|
46844
47243
|
viewers = /* @__PURE__ */ new Map();
|
|
47244
|
+
pendingViewers = /* @__PURE__ */ new Map();
|
|
46845
47245
|
// A poll already in flight can arrive after its pagehide release. Keep that document closed.
|
|
46846
47246
|
releasedViewers = /* @__PURE__ */ new Set();
|
|
46847
47247
|
leaseTimeoutMs;
|
|
47248
|
+
startupTimeoutMs;
|
|
46848
47249
|
closeGraceMs;
|
|
46849
47250
|
timerLatenessToleranceMs;
|
|
46850
47251
|
timer = null;
|
|
@@ -46853,35 +47254,72 @@ var ViewerLifecycle = class {
|
|
|
46853
47254
|
get activeViewerCount() {
|
|
46854
47255
|
return this.viewers.size;
|
|
46855
47256
|
}
|
|
46856
|
-
|
|
47257
|
+
get pendingViewerCount() {
|
|
47258
|
+
return this.pendingViewers.size;
|
|
47259
|
+
}
|
|
47260
|
+
reserveViewer(leaseId) {
|
|
47261
|
+
if (this.stopped) return false;
|
|
47262
|
+
this.pendingViewers.set(leaseId, { phase: "opening" });
|
|
47263
|
+
this.scheduleActivityCheck();
|
|
47264
|
+
return true;
|
|
47265
|
+
}
|
|
47266
|
+
armViewerReservation(leaseId) {
|
|
47267
|
+
if (this.stopped || !this.pendingViewers.has(leaseId)) return false;
|
|
47268
|
+
this.pendingViewers.set(leaseId, {
|
|
47269
|
+
phase: "startup",
|
|
47270
|
+
deadline: Date.now() + this.startupTimeoutMs,
|
|
47271
|
+
timeoutMs: this.startupTimeoutMs
|
|
47272
|
+
});
|
|
47273
|
+
this.scheduleActivityCheck();
|
|
47274
|
+
return true;
|
|
47275
|
+
}
|
|
47276
|
+
cancelViewerReservation(leaseId) {
|
|
47277
|
+
if (this.stopped || !this.pendingViewers.delete(leaseId)) return;
|
|
47278
|
+
this.scheduleNext();
|
|
47279
|
+
}
|
|
47280
|
+
heartbeat(viewerId, pendingLeaseId) {
|
|
46857
47281
|
if (this.stopped || this.releasedViewers.has(viewerId)) return;
|
|
47282
|
+
if (pendingLeaseId !== void 0) this.pendingViewers.delete(pendingLeaseId);
|
|
46858
47283
|
if (!this.viewerHasConnected) {
|
|
46859
47284
|
this.viewerHasConnected = true;
|
|
46860
47285
|
this.options.onFirstViewerConnected?.();
|
|
46861
47286
|
}
|
|
46862
47287
|
this.viewers.set(viewerId, Date.now());
|
|
46863
|
-
this.
|
|
47288
|
+
this.scheduleActivityCheck();
|
|
46864
47289
|
}
|
|
46865
47290
|
release(viewerId) {
|
|
46866
47291
|
if (this.stopped) return;
|
|
46867
47292
|
this.releasedViewers.add(viewerId);
|
|
46868
47293
|
if (!this.viewers.delete(viewerId)) return;
|
|
46869
|
-
|
|
46870
|
-
else this.scheduleLeaseCheck();
|
|
47294
|
+
this.scheduleNext();
|
|
46871
47295
|
}
|
|
46872
47296
|
close() {
|
|
46873
47297
|
this.stopped = true;
|
|
46874
47298
|
this.clearTimer();
|
|
46875
47299
|
this.viewers.clear();
|
|
47300
|
+
this.pendingViewers.clear();
|
|
46876
47301
|
this.releasedViewers.clear();
|
|
46877
47302
|
}
|
|
46878
|
-
|
|
46879
|
-
if (this.
|
|
46880
|
-
|
|
46881
|
-
|
|
47303
|
+
scheduleNext() {
|
|
47304
|
+
if (this.viewers.size > 0 || this.pendingViewers.size > 0) this.scheduleActivityCheck();
|
|
47305
|
+
else this.scheduleEmptyShutdown();
|
|
47306
|
+
}
|
|
47307
|
+
scheduleActivityCheck() {
|
|
47308
|
+
if (this.stopped) return;
|
|
47309
|
+
const deadlines = [
|
|
47310
|
+
...Array.from(this.viewers.values(), (heartbeat) => heartbeat + this.leaseTimeoutMs),
|
|
47311
|
+
...Array.from(this.pendingViewers.values()).filter(
|
|
47312
|
+
(pending) => pending.phase === "startup"
|
|
47313
|
+
).map((pending) => pending.deadline)
|
|
47314
|
+
];
|
|
47315
|
+
if (deadlines.length === 0) {
|
|
47316
|
+
this.clearTimer();
|
|
47317
|
+
return;
|
|
47318
|
+
}
|
|
47319
|
+
this.schedule("activity", Math.min(...deadlines));
|
|
46882
47320
|
}
|
|
46883
47321
|
scheduleEmptyShutdown() {
|
|
46884
|
-
if (this.stopped || this.viewers.size > 0) return;
|
|
47322
|
+
if (this.stopped || this.viewers.size > 0 || this.pendingViewers.size > 0) return;
|
|
46885
47323
|
this.schedule("empty", Date.now() + this.closeGraceMs);
|
|
46886
47324
|
}
|
|
46887
47325
|
schedule(kind, deadline) {
|
|
@@ -46895,23 +47333,33 @@ var ViewerLifecycle = class {
|
|
|
46895
47333
|
const now = Date.now();
|
|
46896
47334
|
if (now - deadline > this.timerLatenessToleranceMs) {
|
|
46897
47335
|
for (const viewerId of this.viewers.keys()) this.viewers.set(viewerId, now);
|
|
46898
|
-
|
|
46899
|
-
|
|
47336
|
+
for (const [leaseId, pending] of this.pendingViewers) {
|
|
47337
|
+
if (pending.phase !== "startup") continue;
|
|
47338
|
+
this.pendingViewers.set(leaseId, {
|
|
47339
|
+
phase: "startup",
|
|
47340
|
+
deadline: now + pending.timeoutMs,
|
|
47341
|
+
timeoutMs: pending.timeoutMs
|
|
47342
|
+
});
|
|
47343
|
+
}
|
|
47344
|
+
this.scheduleNext();
|
|
46900
47345
|
return;
|
|
46901
47346
|
}
|
|
46902
|
-
if (kind === "
|
|
47347
|
+
if (kind === "activity") {
|
|
46903
47348
|
for (const [viewerId, lastHeartbeat] of this.viewers) {
|
|
46904
47349
|
if (now - lastHeartbeat >= this.leaseTimeoutMs) this.viewers.delete(viewerId);
|
|
46905
47350
|
}
|
|
46906
|
-
|
|
46907
|
-
|
|
47351
|
+
for (const [leaseId, pending] of this.pendingViewers) {
|
|
47352
|
+
if (pending.phase !== "startup") continue;
|
|
47353
|
+
if (now >= pending.deadline) this.pendingViewers.delete(leaseId);
|
|
47354
|
+
}
|
|
47355
|
+
this.scheduleNext();
|
|
46908
47356
|
return;
|
|
46909
47357
|
}
|
|
46910
|
-
if (this.viewers.size === 0) {
|
|
47358
|
+
if (this.viewers.size === 0 && this.pendingViewers.size === 0) {
|
|
46911
47359
|
this.stopped = true;
|
|
46912
47360
|
this.options.onAllViewersClosed();
|
|
46913
47361
|
} else {
|
|
46914
|
-
this.
|
|
47362
|
+
this.scheduleActivityCheck();
|
|
46915
47363
|
}
|
|
46916
47364
|
}
|
|
46917
47365
|
clearTimer() {
|
|
@@ -46921,6 +47369,7 @@ var ViewerLifecycle = class {
|
|
|
46921
47369
|
};
|
|
46922
47370
|
|
|
46923
47371
|
// src/server/start-server.ts
|
|
47372
|
+
var RUNTIME_STOPPING_REASON = "runtime-stopping";
|
|
46924
47373
|
async function startServer(service, options = {}) {
|
|
46925
47374
|
const host = "127.0.0.1";
|
|
46926
47375
|
const security = { expectedHost: null, expectedOrigin: null };
|
|
@@ -46960,6 +47409,33 @@ async function startServer(service, options = {}) {
|
|
|
46960
47409
|
origin,
|
|
46961
47410
|
firstViewerConnected,
|
|
46962
47411
|
allViewersClosed,
|
|
47412
|
+
reserveViewer: () => {
|
|
47413
|
+
if (!viewerLifecycle) return null;
|
|
47414
|
+
const leaseId = randomUUID4();
|
|
47415
|
+
if (!viewerLifecycle.reserveViewer(leaseId)) {
|
|
47416
|
+
throw new RvwError(
|
|
47417
|
+
"PROCESS_FAILED",
|
|
47418
|
+
"rvw runtime\u306F\u505C\u6B62\u51E6\u7406\u4E2D\u306E\u305F\u3081viewer\u3092\u8FFD\u52A0\u3067\u304D\u307E\u305B\u3093\u3002",
|
|
47419
|
+
{
|
|
47420
|
+
details: { reason: RUNTIME_STOPPING_REASON },
|
|
47421
|
+
suggestions: ["rvw open\u3092\u518D\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002"]
|
|
47422
|
+
}
|
|
47423
|
+
);
|
|
47424
|
+
}
|
|
47425
|
+
return leaseId;
|
|
47426
|
+
},
|
|
47427
|
+
armViewerReservation: (leaseId) => {
|
|
47428
|
+
if (!viewerLifecycle || viewerLifecycle.armViewerReservation(leaseId)) return;
|
|
47429
|
+
throw new RvwError(
|
|
47430
|
+
"PROCESS_FAILED",
|
|
47431
|
+
"rvw runtime\u306F\u505C\u6B62\u51E6\u7406\u4E2D\u306E\u305F\u3081viewer\u3092\u8FFD\u52A0\u3067\u304D\u307E\u305B\u3093\u3002",
|
|
47432
|
+
{
|
|
47433
|
+
details: { reason: RUNTIME_STOPPING_REASON },
|
|
47434
|
+
suggestions: ["rvw open\u3092\u518D\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002"]
|
|
47435
|
+
}
|
|
47436
|
+
);
|
|
47437
|
+
},
|
|
47438
|
+
cancelViewerReservation: (leaseId) => viewerLifecycle?.cancelViewerReservation(leaseId),
|
|
46963
47439
|
close: () => closePromise ??= (async () => {
|
|
46964
47440
|
viewerLifecycle?.close();
|
|
46965
47441
|
await new Promise((closeResolve, closeReject) => {
|
|
@@ -46974,7 +47450,7 @@ async function startServer(service, options = {}) {
|
|
|
46974
47450
|
}
|
|
46975
47451
|
|
|
46976
47452
|
// src/server/agent-socket.ts
|
|
46977
|
-
import { createHash as createHash5, randomUUID as
|
|
47453
|
+
import { createHash as createHash5, randomUUID as randomUUID5 } from "node:crypto";
|
|
46978
47454
|
import {
|
|
46979
47455
|
chmodSync as chmodSync2,
|
|
46980
47456
|
existsSync as existsSync5,
|
|
@@ -46990,7 +47466,8 @@ import os4 from "node:os";
|
|
|
46990
47466
|
import path9 from "node:path";
|
|
46991
47467
|
var MAX_CLI_STDIN_BYTES = 40 * 1024 * 1024;
|
|
46992
47468
|
var MAX_AGENT_MESSAGE_BYTES = MAX_CLI_STDIN_BYTES + 64 * 1024;
|
|
46993
|
-
var AGENT_SOCKET_PROTOCOL_VERSION =
|
|
47469
|
+
var AGENT_SOCKET_PROTOCOL_VERSION = 4;
|
|
47470
|
+
var RUNTIME_VIEWER_OPEN_OPERATION = "viewer.open";
|
|
46994
47471
|
var AGENT_SOCKET_RESTART_SUGGESTION = "\u8D77\u52D5\u4E2D\u306Ervw viewer\u3092\u505C\u6B62\u3057\u3001\u66F4\u65B0\u5F8C\u306Ervw open\u3067\u518D\u8D77\u52D5\u3057\u3066\u304F\u3060\u3055\u3044\u3002";
|
|
46995
47472
|
var DEFAULT_CONNECT_TIMEOUT_MS = 2e3;
|
|
46996
47473
|
var DEFAULT_OPERATION_TIMEOUT_MS = 18e4;
|
|
@@ -47003,6 +47480,19 @@ var agentRequestEnvelopeSchema = external_exports.object({
|
|
|
47003
47480
|
input: external_exports.unknown(),
|
|
47004
47481
|
expectedDatabasePath: external_exports.string().min(1).optional()
|
|
47005
47482
|
}).strict();
|
|
47483
|
+
var runtimeViewerOpenInputSchema = external_exports.object({
|
|
47484
|
+
reference: external_exports.string().min(1).optional(),
|
|
47485
|
+
cwd: external_exports.string().min(1),
|
|
47486
|
+
requestedPort: external_exports.number().int().min(0).max(65535)
|
|
47487
|
+
}).strict();
|
|
47488
|
+
var runtimeViewerOpenResultSchema = external_exports.object({
|
|
47489
|
+
url: external_exports.string().url(),
|
|
47490
|
+
origin: external_exports.string().url(),
|
|
47491
|
+
port: external_exports.number().int().min(1).max(65535),
|
|
47492
|
+
pullRequestId: external_exports.string().min(1),
|
|
47493
|
+
ownerPid: external_exports.number().int().positive(),
|
|
47494
|
+
viewerLeaseId: external_exports.uuid().optional()
|
|
47495
|
+
}).strict();
|
|
47006
47496
|
function explicitAgentSocketPath() {
|
|
47007
47497
|
const configuredPath = process.env.RVW_AGENT_SOCKET_PATH;
|
|
47008
47498
|
if (configuredPath === void 0) return null;
|
|
@@ -47058,7 +47548,10 @@ function parseOperationInput(operation, value) {
|
|
|
47058
47548
|
if (!parsed.success) throw invalidSocketInput(parsed.error);
|
|
47059
47549
|
return parsed.data;
|
|
47060
47550
|
}
|
|
47061
|
-
|
|
47551
|
+
function resolveDatabaseIdentity(databaseFilePath) {
|
|
47552
|
+
return databaseFilePath === ":memory:" ? databaseFilePath : path9.resolve(databaseFilePath);
|
|
47553
|
+
}
|
|
47554
|
+
function validateAgentRequest(rawRequest, databaseFilePath) {
|
|
47062
47555
|
const request = parseRequest(rawRequest);
|
|
47063
47556
|
if (request.protocolVersion !== AGENT_SOCKET_PROTOCOL_VERSION) {
|
|
47064
47557
|
throw new RvwError("STALE_PROTOCOL", "Agent socket protocol version\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002", {
|
|
@@ -47069,23 +47562,30 @@ async function dispatchAgentSocketRequest(service, rawRequest) {
|
|
|
47069
47562
|
suggestions: [AGENT_SOCKET_RESTART_SUGGESTION]
|
|
47070
47563
|
});
|
|
47071
47564
|
}
|
|
47072
|
-
if (request.expectedDatabasePath !== void 0 &&
|
|
47565
|
+
if (request.expectedDatabasePath !== void 0 && databaseFilePath !== void 0 && resolveDatabaseIdentity(request.expectedDatabasePath) !== resolveDatabaseIdentity(databaseFilePath)) {
|
|
47073
47566
|
throw new RvwError("DATABASE_ERROR", "Agent socket\u304C\u5225\u306Edatabase\u3092\u4F7F\u7528\u3057\u3066\u3044\u307E\u3059\u3002", {
|
|
47074
47567
|
details: {
|
|
47075
47568
|
agentSocketDatabaseMismatch: true,
|
|
47076
|
-
expectedDatabasePath:
|
|
47077
|
-
actualDatabasePath:
|
|
47569
|
+
expectedDatabasePath: resolveDatabaseIdentity(request.expectedDatabasePath),
|
|
47570
|
+
actualDatabasePath: resolveDatabaseIdentity(databaseFilePath)
|
|
47078
47571
|
}
|
|
47079
47572
|
});
|
|
47080
47573
|
}
|
|
47574
|
+
return request;
|
|
47575
|
+
}
|
|
47576
|
+
function pingResult(databaseFilePath) {
|
|
47577
|
+
return {
|
|
47578
|
+
protocolVersion: AGENT_SOCKET_PROTOCOL_VERSION,
|
|
47579
|
+
databasePath: resolveDatabaseIdentity(databaseFilePath),
|
|
47580
|
+
ownerPid: process.pid
|
|
47581
|
+
};
|
|
47582
|
+
}
|
|
47583
|
+
async function dispatchAgentSocketRequest(service, rawRequest) {
|
|
47584
|
+
const request = validateAgentRequest(rawRequest, service.database?.filePath);
|
|
47081
47585
|
if (request.operation === "ping") {
|
|
47082
47586
|
const ping = external_exports.object({}).strict().safeParse(request.input);
|
|
47083
47587
|
if (!ping.success) throw invalidSocketInput(ping.error);
|
|
47084
|
-
return
|
|
47085
|
-
protocolVersion: AGENT_SOCKET_PROTOCOL_VERSION,
|
|
47086
|
-
databasePath: path9.resolve(service.database.filePath),
|
|
47087
|
-
ownerPid: process.pid
|
|
47088
|
-
};
|
|
47588
|
+
return pingResult(service.database.filePath);
|
|
47089
47589
|
}
|
|
47090
47590
|
if (!Object.hasOwn(agentCommandInputSchemas, request.operation)) {
|
|
47091
47591
|
throw new RvwError("INVALID_INPUT", `\u672A\u5BFE\u5FDC\u306EAgent socket operation\u3067\u3059: ${request.operation}`);
|
|
@@ -47390,6 +47890,38 @@ async function tryAgentSocketRequest(operation, input, options = {}) {
|
|
|
47390
47890
|
});
|
|
47391
47891
|
});
|
|
47392
47892
|
}
|
|
47893
|
+
async function tryRuntimeViewerOpen(input, databaseFilePath = databasePathConfiguration().filePath, options = {}) {
|
|
47894
|
+
const parsedInput = runtimeViewerOpenInputSchema.safeParse(input);
|
|
47895
|
+
if (!parsedInput.success) throw invalidSocketInput(parsedInput.error);
|
|
47896
|
+
const response = await tryAgentSocketRequest(
|
|
47897
|
+
RUNTIME_VIEWER_OPEN_OPERATION,
|
|
47898
|
+
parsedInput.data,
|
|
47899
|
+
{
|
|
47900
|
+
expectedDatabasePath: databaseFilePath,
|
|
47901
|
+
requireSocket: false,
|
|
47902
|
+
...options
|
|
47903
|
+
}
|
|
47904
|
+
);
|
|
47905
|
+
if (!response.available) return response;
|
|
47906
|
+
const parsedResult = runtimeViewerOpenResultSchema.safeParse(response.result);
|
|
47907
|
+
if (!parsedResult.success) {
|
|
47908
|
+
throw new RvwError("PROCESS_FAILED", "\u8D77\u52D5\u4E2D\u306Ervw runtime\u304B\u3089\u4E0D\u6B63\u306A\u5FDC\u7B54\u3092\u53D7\u4FE1\u3057\u307E\u3057\u305F\u3002", {
|
|
47909
|
+
details: { issues: parsedResult.error.issues },
|
|
47910
|
+
suggestions: [AGENT_SOCKET_RESTART_SUGGESTION]
|
|
47911
|
+
});
|
|
47912
|
+
}
|
|
47913
|
+
return {
|
|
47914
|
+
available: true,
|
|
47915
|
+
result: {
|
|
47916
|
+
url: parsedResult.data.url,
|
|
47917
|
+
origin: parsedResult.data.origin,
|
|
47918
|
+
port: parsedResult.data.port,
|
|
47919
|
+
pullRequestId: parsedResult.data.pullRequestId,
|
|
47920
|
+
ownerPid: parsedResult.data.ownerPid,
|
|
47921
|
+
...parsedResult.data.viewerLeaseId === void 0 ? {} : { viewerLeaseId: parsedResult.data.viewerLeaseId }
|
|
47922
|
+
}
|
|
47923
|
+
};
|
|
47924
|
+
}
|
|
47393
47925
|
async function inspectAgentTransport(databaseFilePath = databasePathConfiguration().filePath) {
|
|
47394
47926
|
const expectedDatabasePath = databaseFilePath === ":memory:" ? databaseFilePath : path9.resolve(databaseFilePath);
|
|
47395
47927
|
const configuredSocketPath = explicitAgentSocketPath();
|
|
@@ -47492,7 +48024,7 @@ function socketOwnerPid(lockPath) {
|
|
|
47492
48024
|
function tryAcquireSocketOwnerLock(socketPath) {
|
|
47493
48025
|
const lockPath = `${socketPath}${OWNER_LOCK_SUFFIX}`;
|
|
47494
48026
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
47495
|
-
const stagingPath = `${lockPath}.${process.pid}.${
|
|
48027
|
+
const stagingPath = `${lockPath}.${process.pid}.${randomUUID5()}.tmp`;
|
|
47496
48028
|
try {
|
|
47497
48029
|
writeFileSync2(stagingPath, `${JSON.stringify({ pid: process.pid })}
|
|
47498
48030
|
`, {
|
|
@@ -47536,7 +48068,7 @@ function releaseSocketOwnerLock(lock) {
|
|
|
47536
48068
|
if (!lock) return;
|
|
47537
48069
|
unlinkIfOwned(lock.path, lock.identity);
|
|
47538
48070
|
}
|
|
47539
|
-
function createAgentServer(
|
|
48071
|
+
function createAgentServer(dispatch) {
|
|
47540
48072
|
const server = net.createServer((socket) => {
|
|
47541
48073
|
const chunks = [];
|
|
47542
48074
|
let bytes = 0;
|
|
@@ -47561,7 +48093,7 @@ function createAgentServer(service) {
|
|
|
47561
48093
|
const request = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
47562
48094
|
response = {
|
|
47563
48095
|
ok: true,
|
|
47564
|
-
result: await
|
|
48096
|
+
result: await dispatch(parseRequest(request))
|
|
47565
48097
|
};
|
|
47566
48098
|
} catch (error51) {
|
|
47567
48099
|
response = { ok: false, error: asRvwError(error51).toJSON() };
|
|
@@ -47589,8 +48121,8 @@ async function listen(server, socketPath) {
|
|
|
47589
48121
|
server.listen(socketPath);
|
|
47590
48122
|
});
|
|
47591
48123
|
}
|
|
47592
|
-
async function
|
|
47593
|
-
const socketPath = agentSocketPath(
|
|
48124
|
+
async function startAgentSocketListener(databaseFilePath, dispatch, options) {
|
|
48125
|
+
const socketPath = agentSocketPath(databaseFilePath);
|
|
47594
48126
|
ensurePrivateSocketDirectory(socketPath);
|
|
47595
48127
|
const retryDelay = options.takeoverRetryMs ?? DEFAULT_TAKEOVER_RETRY_MS;
|
|
47596
48128
|
let server = null;
|
|
@@ -47598,9 +48130,12 @@ async function startAgentSocket(service, options = {}) {
|
|
|
47598
48130
|
let ownerLock = null;
|
|
47599
48131
|
let retryTimer;
|
|
47600
48132
|
let acquisition = null;
|
|
48133
|
+
let listenerDrain = null;
|
|
48134
|
+
let stopPromise = null;
|
|
48135
|
+
let releasePromise = null;
|
|
47601
48136
|
let closed = false;
|
|
47602
48137
|
const scheduleTakeover = () => {
|
|
47603
|
-
if (closed || server || retryTimer) return;
|
|
48138
|
+
if (!options.retryOwnership || closed || server || retryTimer) return;
|
|
47604
48139
|
retryTimer = setTimeout(() => {
|
|
47605
48140
|
retryTimer = void 0;
|
|
47606
48141
|
void acquire().catch(() => scheduleTakeover());
|
|
@@ -47629,7 +48164,7 @@ async function startAgentSocket(service, options = {}) {
|
|
|
47629
48164
|
throw error51;
|
|
47630
48165
|
}
|
|
47631
48166
|
}
|
|
47632
|
-
const candidate = createAgentServer(
|
|
48167
|
+
const candidate = createAgentServer(dispatch);
|
|
47633
48168
|
try {
|
|
47634
48169
|
await listen(candidate, socketPath);
|
|
47635
48170
|
} catch (error51) {
|
|
@@ -47661,12 +48196,16 @@ async function startAgentSocket(service, options = {}) {
|
|
|
47661
48196
|
ownerLock = candidateLock;
|
|
47662
48197
|
candidate.on("error", () => {
|
|
47663
48198
|
if (server !== candidate) return;
|
|
47664
|
-
const failedIdentity = identity;
|
|
47665
|
-
const failedOwnerLock = ownerLock;
|
|
47666
48199
|
server = null;
|
|
48200
|
+
listenerDrain = new Promise((resolve) => candidate.close(() => resolve()));
|
|
48201
|
+
if (!options.retryOwnership) {
|
|
48202
|
+
return;
|
|
48203
|
+
}
|
|
48204
|
+
const failedIdentity = identity;
|
|
47667
48205
|
identity = null;
|
|
48206
|
+
const failedOwnerLock = ownerLock;
|
|
47668
48207
|
ownerLock = null;
|
|
47669
|
-
|
|
48208
|
+
void listenerDrain.then(() => {
|
|
47670
48209
|
unlinkIfOwned(socketPath, failedIdentity);
|
|
47671
48210
|
releaseSocketOwnerLock(failedOwnerLock);
|
|
47672
48211
|
scheduleTakeover();
|
|
@@ -47680,33 +48219,128 @@ async function startAgentSocket(service, options = {}) {
|
|
|
47680
48219
|
}
|
|
47681
48220
|
};
|
|
47682
48221
|
await acquire();
|
|
47683
|
-
|
|
47684
|
-
|
|
47685
|
-
get owned() {
|
|
47686
|
-
return server !== null;
|
|
47687
|
-
},
|
|
47688
|
-
close: async () => {
|
|
48222
|
+
const stopAccepting = async () => {
|
|
48223
|
+
await (stopPromise ??= (async () => {
|
|
47689
48224
|
closed = true;
|
|
47690
48225
|
if (retryTimer) clearTimeout(retryTimer);
|
|
47691
48226
|
await acquisition;
|
|
48227
|
+
if (listenerDrain) await listenerDrain;
|
|
47692
48228
|
const ownedServer = server;
|
|
47693
|
-
const ownedIdentity = identity;
|
|
47694
|
-
const ownedOwnerLock = ownerLock;
|
|
47695
48229
|
server = null;
|
|
47696
|
-
|
|
47697
|
-
|
|
47698
|
-
|
|
47699
|
-
|
|
47700
|
-
|
|
47701
|
-
|
|
48230
|
+
if (!ownedServer) return;
|
|
48231
|
+
listenerDrain = new Promise(
|
|
48232
|
+
(resolve, reject) => ownedServer.close((error51) => error51 ? reject(error51) : resolve())
|
|
48233
|
+
);
|
|
48234
|
+
await listenerDrain;
|
|
48235
|
+
})());
|
|
48236
|
+
};
|
|
48237
|
+
const releaseOwnership = async () => {
|
|
48238
|
+
await (releasePromise ??= (async () => {
|
|
47702
48239
|
try {
|
|
47703
|
-
await
|
|
47704
|
-
(resolve, reject) => ownedServer.close((error51) => error51 ? reject(error51) : resolve())
|
|
47705
|
-
);
|
|
48240
|
+
await stopAccepting();
|
|
47706
48241
|
} finally {
|
|
47707
|
-
|
|
47708
|
-
|
|
48242
|
+
const ownedIdentity = identity;
|
|
48243
|
+
const ownedOwnerLock = ownerLock;
|
|
48244
|
+
identity = null;
|
|
48245
|
+
ownerLock = null;
|
|
48246
|
+
try {
|
|
48247
|
+
unlinkIfOwned(socketPath, ownedIdentity);
|
|
48248
|
+
} finally {
|
|
48249
|
+
releaseSocketOwnerLock(ownedOwnerLock);
|
|
48250
|
+
}
|
|
48251
|
+
}
|
|
48252
|
+
})());
|
|
48253
|
+
};
|
|
48254
|
+
return {
|
|
48255
|
+
path: socketPath,
|
|
48256
|
+
get owned() {
|
|
48257
|
+
return ownerLock !== null;
|
|
48258
|
+
},
|
|
48259
|
+
stopAccepting,
|
|
48260
|
+
releaseOwnership,
|
|
48261
|
+
close: releaseOwnership
|
|
48262
|
+
};
|
|
48263
|
+
}
|
|
48264
|
+
async function startRuntimeAgentSocket(databaseFilePath) {
|
|
48265
|
+
let handler = null;
|
|
48266
|
+
let resolveHandler;
|
|
48267
|
+
let rejectHandler;
|
|
48268
|
+
const handlerPromise = new Promise((resolve, reject) => {
|
|
48269
|
+
resolveHandler = resolve;
|
|
48270
|
+
rejectHandler = reject;
|
|
48271
|
+
});
|
|
48272
|
+
void handlerPromise.catch(() => {
|
|
48273
|
+
});
|
|
48274
|
+
let accepting = true;
|
|
48275
|
+
const rejectUninitializedHandler = () => {
|
|
48276
|
+
if (handler) return;
|
|
48277
|
+
rejectHandler?.(new RvwError("PROCESS_FAILED", "rvw runtime\u304C\u521D\u671F\u5316\u3055\u308C\u308B\u524D\u306B\u505C\u6B62\u3057\u307E\u3057\u305F\u3002"));
|
|
48278
|
+
resolveHandler = void 0;
|
|
48279
|
+
rejectHandler = void 0;
|
|
48280
|
+
};
|
|
48281
|
+
const running = await startAgentSocketListener(
|
|
48282
|
+
databaseFilePath,
|
|
48283
|
+
async (rawRequest) => {
|
|
48284
|
+
const request = validateAgentRequest(rawRequest, databaseFilePath);
|
|
48285
|
+
if (request.operation === "ping") {
|
|
48286
|
+
const ping = external_exports.object({}).strict().safeParse(request.input);
|
|
48287
|
+
if (!ping.success) throw invalidSocketInput(ping.error);
|
|
48288
|
+
return pingResult(databaseFilePath);
|
|
48289
|
+
}
|
|
48290
|
+
if (request.operation === RUNTIME_VIEWER_OPEN_OPERATION) {
|
|
48291
|
+
const parsed = runtimeViewerOpenInputSchema.safeParse(request.input);
|
|
48292
|
+
if (!parsed.success) throw invalidSocketInput(parsed.error);
|
|
48293
|
+
return await (await handlerPromise).openViewer({
|
|
48294
|
+
...parsed.data.reference === void 0 ? {} : { reference: parsed.data.reference },
|
|
48295
|
+
cwd: parsed.data.cwd,
|
|
48296
|
+
requestedPort: parsed.data.requestedPort
|
|
48297
|
+
});
|
|
48298
|
+
}
|
|
48299
|
+
return await dispatchAgentSocketRequest((await handlerPromise).service, request);
|
|
48300
|
+
},
|
|
48301
|
+
{ retryOwnership: false }
|
|
48302
|
+
);
|
|
48303
|
+
return {
|
|
48304
|
+
path: running.path,
|
|
48305
|
+
get owned() {
|
|
48306
|
+
return running.owned;
|
|
48307
|
+
},
|
|
48308
|
+
setHandler(value) {
|
|
48309
|
+
if (!running.owned || !accepting) {
|
|
48310
|
+
throw new RvwError("PROCESS_FAILED", "\u6240\u6709\u3057\u3066\u3044\u306A\u3044runtime socket\u306F\u521D\u671F\u5316\u3067\u304D\u307E\u305B\u3093\u3002");
|
|
48311
|
+
}
|
|
48312
|
+
if (handler) {
|
|
48313
|
+
throw new RvwError("INTERNAL_ERROR", "runtime socket\u306F\u521D\u671F\u5316\u6E08\u307F\u3067\u3059\u3002", {
|
|
48314
|
+
status: 500
|
|
48315
|
+
});
|
|
48316
|
+
}
|
|
48317
|
+
if (resolveDatabaseIdentity(value.service.database.filePath) !== resolveDatabaseIdentity(databaseFilePath)) {
|
|
48318
|
+
throw new RvwError("DATABASE_ERROR", "runtime\u3068Agent socket\u306Edatabase\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002", {
|
|
48319
|
+
details: {
|
|
48320
|
+
socketDatabasePath: resolveDatabaseIdentity(databaseFilePath),
|
|
48321
|
+
runtimeDatabasePath: resolveDatabaseIdentity(value.service.database.filePath)
|
|
48322
|
+
}
|
|
48323
|
+
});
|
|
47709
48324
|
}
|
|
48325
|
+
handler = value;
|
|
48326
|
+
resolveHandler?.(value);
|
|
48327
|
+
resolveHandler = void 0;
|
|
48328
|
+
rejectHandler = void 0;
|
|
48329
|
+
},
|
|
48330
|
+
stopAccepting: async () => {
|
|
48331
|
+
accepting = false;
|
|
48332
|
+
rejectUninitializedHandler();
|
|
48333
|
+
await running.stopAccepting();
|
|
48334
|
+
},
|
|
48335
|
+
releaseOwnership: async () => {
|
|
48336
|
+
accepting = false;
|
|
48337
|
+
rejectUninitializedHandler();
|
|
48338
|
+
await running.releaseOwnership();
|
|
48339
|
+
},
|
|
48340
|
+
close: async () => {
|
|
48341
|
+
accepting = false;
|
|
48342
|
+
rejectUninitializedHandler();
|
|
48343
|
+
await running.releaseOwnership();
|
|
47710
48344
|
}
|
|
47711
48345
|
};
|
|
47712
48346
|
}
|
|
@@ -48067,6 +48701,9 @@ function formatCommentListOutput(result, state) {
|
|
|
48067
48701
|
var MAX_STDIN_BYTES = MAX_CLI_STDIN_BYTES;
|
|
48068
48702
|
var OPEN_WORKER_READY_TIMEOUT_MS = 12e4;
|
|
48069
48703
|
var OPEN_WORKER_PARENT_TIMEOUT_PADDING_MS = 5e3;
|
|
48704
|
+
var RUNTIME_REUSE_RETRY_MS = 50;
|
|
48705
|
+
var RUNTIME_VIEWER_HEARTBEAT_INTERVAL_MS = 3e4;
|
|
48706
|
+
var RUNTIME_VIEWER_REQUEST_TIMEOUT_MS = 5e3;
|
|
48070
48707
|
function writeJson(value) {
|
|
48071
48708
|
process.stdout.write(`${JSON.stringify(value)}
|
|
48072
48709
|
`);
|
|
@@ -48162,6 +48799,11 @@ function errorFromOpenWorker(error51) {
|
|
|
48162
48799
|
...error51.details === void 0 ? {} : { details: error51.details }
|
|
48163
48800
|
});
|
|
48164
48801
|
}
|
|
48802
|
+
function isRuntimeStoppingError(error51) {
|
|
48803
|
+
if (!(error51 instanceof RvwError) || error51.code !== "PROCESS_FAILED") return false;
|
|
48804
|
+
if (!error51.details || typeof error51.details !== "object") return false;
|
|
48805
|
+
return error51.details.reason === RUNTIME_STOPPING_REASON;
|
|
48806
|
+
}
|
|
48165
48807
|
async function completeBackgroundOpen(child, launchBrowser, options = {}) {
|
|
48166
48808
|
const readyTimeoutMs = options.readyTimeoutMs ?? OPEN_WORKER_READY_TIMEOUT_MS;
|
|
48167
48809
|
const viewerTimeoutMs = options.viewerTimeoutMs ?? DEFAULT_VIEWER_STARTUP_TIMEOUT_MS + OPEN_WORKER_PARENT_TIMEOUT_PADDING_MS;
|
|
@@ -48285,11 +48927,31 @@ function forkOpenWorker(reference, port) {
|
|
|
48285
48927
|
});
|
|
48286
48928
|
}
|
|
48287
48929
|
async function startBackgroundOpen(reference, port, dependencies = {}) {
|
|
48930
|
+
const input = {
|
|
48931
|
+
...reference === void 0 ? {} : { reference },
|
|
48932
|
+
cwd: process.cwd(),
|
|
48933
|
+
requestedPort: port
|
|
48934
|
+
};
|
|
48935
|
+
const launchBrowser = dependencies.launchBrowser ?? (async (url2) => await open_default(url2));
|
|
48936
|
+
let existing = null;
|
|
48937
|
+
try {
|
|
48938
|
+
existing = await (dependencies.tryRuntimeOpen ?? tryRuntimeViewerOpen)(input);
|
|
48939
|
+
} catch (error51) {
|
|
48940
|
+
if (!isRuntimeStoppingError(error51)) throw error51;
|
|
48941
|
+
}
|
|
48942
|
+
if (existing?.available) {
|
|
48943
|
+
await launchBrowser(existing.result.url);
|
|
48944
|
+
return existing.result.url;
|
|
48945
|
+
}
|
|
48946
|
+
if (existing?.reason === "database-mismatch") {
|
|
48947
|
+
throw new RvwError(
|
|
48948
|
+
"AGENT_SOCKET_UNAVAILABLE",
|
|
48949
|
+
"\u8D77\u52D5\u4E2D\u306Ervw runtime\u304C\u5225\u306Edatabase\u3092\u4F7F\u7528\u3057\u3066\u3044\u307E\u3059\u3002",
|
|
48950
|
+
{ details: existing.details }
|
|
48951
|
+
);
|
|
48952
|
+
}
|
|
48288
48953
|
const child = (dependencies.forkWorker ?? forkOpenWorker)(reference, port);
|
|
48289
|
-
return await completeBackgroundOpen(
|
|
48290
|
-
child,
|
|
48291
|
-
dependencies.launchBrowser ?? (async (url2) => await open_default(url2))
|
|
48292
|
-
);
|
|
48954
|
+
return await completeBackgroundOpen(child, launchBrowser);
|
|
48293
48955
|
}
|
|
48294
48956
|
async function sendOpenWorkerMessage(message) {
|
|
48295
48957
|
if (!process.send || !process.connected) return false;
|
|
@@ -48321,17 +48983,208 @@ async function waitForInitialViewer(firstViewerConnected, timeoutMs = DEFAULT_VI
|
|
|
48321
48983
|
void firstViewerConnected.then(() => finish("connected"));
|
|
48322
48984
|
});
|
|
48323
48985
|
}
|
|
48324
|
-
|
|
48986
|
+
function runtimeViewerOpenInput(reference, cwd, requestedPort) {
|
|
48987
|
+
return {
|
|
48988
|
+
...reference === void 0 ? {} : { reference },
|
|
48989
|
+
cwd,
|
|
48990
|
+
requestedPort
|
|
48991
|
+
};
|
|
48992
|
+
}
|
|
48993
|
+
function createRuntimeAgentSocketHandler(activeRuntime, running) {
|
|
48994
|
+
return {
|
|
48995
|
+
service: activeRuntime.service,
|
|
48996
|
+
openViewer: async (input) => {
|
|
48997
|
+
if (input.requestedPort !== 0 && input.requestedPort !== running.port) {
|
|
48998
|
+
throw new RvwError(
|
|
48999
|
+
"INVALID_INPUT",
|
|
49000
|
+
`\u540C\u3058database\u306Ervw runtime\u306Fport ${running.port} \u3067\u8D77\u52D5\u6E08\u307F\u3067\u3059\u3002`,
|
|
49001
|
+
{
|
|
49002
|
+
details: { activePort: running.port, requestedPort: input.requestedPort },
|
|
49003
|
+
suggestions: [
|
|
49004
|
+
"\u65E2\u5B58runtime\u3092\u505C\u6B62\u3057\u3066\u304B\u3089\u6307\u5B9Aport\u3067\u518D\u8D77\u52D5\u3059\u308B\u304B\u3001--port\u3092\u7701\u7565\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
49005
|
+
]
|
|
49006
|
+
}
|
|
49007
|
+
);
|
|
49008
|
+
}
|
|
49009
|
+
const viewerLeaseId = running.reserveViewer();
|
|
49010
|
+
try {
|
|
49011
|
+
const opened = await activeRuntime.service.openPullRequest(input.reference, input.cwd);
|
|
49012
|
+
if (viewerLeaseId !== null) running.armViewerReservation(viewerLeaseId);
|
|
49013
|
+
const url2 = new URL(running.origin);
|
|
49014
|
+
url2.searchParams.set("pullRequestId", opened.pullRequest.id);
|
|
49015
|
+
if (viewerLeaseId !== null) url2.searchParams.set(VIEWER_OPEN_LEASE_QUERY, viewerLeaseId);
|
|
49016
|
+
return {
|
|
49017
|
+
url: url2.toString(),
|
|
49018
|
+
origin: running.origin,
|
|
49019
|
+
port: running.port,
|
|
49020
|
+
pullRequestId: opened.pullRequest.id,
|
|
49021
|
+
ownerPid: process.pid,
|
|
49022
|
+
...viewerLeaseId === null ? {} : { viewerLeaseId }
|
|
49023
|
+
};
|
|
49024
|
+
} catch (error51) {
|
|
49025
|
+
if (viewerLeaseId !== null) running.cancelViewerReservation(viewerLeaseId);
|
|
49026
|
+
throw error51;
|
|
49027
|
+
}
|
|
49028
|
+
}
|
|
49029
|
+
};
|
|
49030
|
+
}
|
|
49031
|
+
async function holdRuntimeViewerLease(result, dependencies = {}) {
|
|
49032
|
+
const viewerLeaseId = result.viewerLeaseId;
|
|
49033
|
+
if (viewerLeaseId === void 0) return;
|
|
49034
|
+
const fetchRequest = dependencies.fetch ?? fetch;
|
|
49035
|
+
const viewerId = randomUUID6();
|
|
49036
|
+
const requestTimeoutMs = dependencies.requestTimeoutMs ?? RUNTIME_VIEWER_REQUEST_TIMEOUT_MS;
|
|
49037
|
+
const heartbeatUrl = new URL("/api/meta/change-sequence", result.origin);
|
|
49038
|
+
const releaseUrl = new URL("/api/meta/viewers/release", result.origin);
|
|
49039
|
+
const heartbeat = async () => {
|
|
49040
|
+
const response = await fetchRequest(heartbeatUrl, {
|
|
49041
|
+
signal: AbortSignal.timeout(requestTimeoutMs),
|
|
49042
|
+
headers: {
|
|
49043
|
+
[VIEWER_ID_HEADER]: viewerId,
|
|
49044
|
+
[VIEWER_OPEN_LEASE_HEADER]: viewerLeaseId
|
|
49045
|
+
}
|
|
49046
|
+
});
|
|
49047
|
+
if (!response.ok) {
|
|
49048
|
+
throw new RvwError("PROCESS_FAILED", "rvw runtime\u306Eviewer lease\u3092\u66F4\u65B0\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002", {
|
|
49049
|
+
details: { status: response.status, origin: result.origin }
|
|
49050
|
+
});
|
|
49051
|
+
}
|
|
49052
|
+
};
|
|
49053
|
+
const stopped = Promise.withResolvers();
|
|
49054
|
+
let heartbeatError;
|
|
49055
|
+
let heartbeatInFlight = false;
|
|
49056
|
+
const onSignal = () => stopped.resolve("signal");
|
|
49057
|
+
process.once("SIGINT", onSignal);
|
|
49058
|
+
process.once("SIGTERM", onSignal);
|
|
49059
|
+
let interval;
|
|
49060
|
+
let registered = false;
|
|
49061
|
+
try {
|
|
49062
|
+
await heartbeat();
|
|
49063
|
+
registered = true;
|
|
49064
|
+
interval = setInterval(() => {
|
|
49065
|
+
if (heartbeatInFlight) return;
|
|
49066
|
+
heartbeatInFlight = true;
|
|
49067
|
+
void heartbeat().catch((error51) => {
|
|
49068
|
+
heartbeatError = error51;
|
|
49069
|
+
stopped.resolve("heartbeat-failed");
|
|
49070
|
+
}).finally(() => {
|
|
49071
|
+
heartbeatInFlight = false;
|
|
49072
|
+
});
|
|
49073
|
+
}, dependencies.heartbeatIntervalMs ?? RUNTIME_VIEWER_HEARTBEAT_INTERVAL_MS);
|
|
49074
|
+
interval.unref();
|
|
49075
|
+
const reason = await stopped.promise;
|
|
49076
|
+
if (reason === "heartbeat-failed") throw heartbeatError;
|
|
49077
|
+
} finally {
|
|
49078
|
+
if (interval) clearInterval(interval);
|
|
49079
|
+
process.removeListener("SIGINT", onSignal);
|
|
49080
|
+
process.removeListener("SIGTERM", onSignal);
|
|
49081
|
+
if (registered) {
|
|
49082
|
+
await fetchRequest(releaseUrl, {
|
|
49083
|
+
method: "POST",
|
|
49084
|
+
signal: AbortSignal.timeout(requestTimeoutMs),
|
|
49085
|
+
headers: {
|
|
49086
|
+
origin: result.origin,
|
|
49087
|
+
"content-type": "application/json"
|
|
49088
|
+
},
|
|
49089
|
+
body: JSON.stringify({ viewerId })
|
|
49090
|
+
}).catch(() => void 0);
|
|
49091
|
+
}
|
|
49092
|
+
}
|
|
49093
|
+
}
|
|
49094
|
+
async function closeOwnedRuntime(agentSocket, running, activeRuntime) {
|
|
49095
|
+
try {
|
|
49096
|
+
await agentSocket?.stopAccepting();
|
|
49097
|
+
} finally {
|
|
49098
|
+
try {
|
|
49099
|
+
await running?.close();
|
|
49100
|
+
} finally {
|
|
49101
|
+
try {
|
|
49102
|
+
activeRuntime?.close();
|
|
49103
|
+
} finally {
|
|
49104
|
+
await agentSocket?.releaseOwnership();
|
|
49105
|
+
}
|
|
49106
|
+
}
|
|
49107
|
+
}
|
|
49108
|
+
}
|
|
49109
|
+
async function acquireRuntimeOrReuseExisting(input, databaseFilePath, timeoutMs = OPEN_WORKER_READY_TIMEOUT_MS, dependencies = {}) {
|
|
49110
|
+
const startSocket = dependencies.startSocket ?? startRuntimeAgentSocket;
|
|
49111
|
+
const tryRuntimeOpen = dependencies.tryRuntimeOpen ?? tryRuntimeViewerOpen;
|
|
49112
|
+
const wait = dependencies.wait ?? (async (milliseconds) => {
|
|
49113
|
+
await new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
49114
|
+
});
|
|
49115
|
+
const now = dependencies.now ?? Date.now;
|
|
49116
|
+
const deadline = now() + timeoutMs;
|
|
49117
|
+
do {
|
|
49118
|
+
const candidate = await startSocket(databaseFilePath);
|
|
49119
|
+
if (candidate.owned) return { kind: "owned", agentSocket: candidate };
|
|
49120
|
+
await candidate.close();
|
|
49121
|
+
let response = null;
|
|
49122
|
+
try {
|
|
49123
|
+
response = await tryRuntimeOpen(input, databaseFilePath);
|
|
49124
|
+
} catch (error51) {
|
|
49125
|
+
if (!isRuntimeStoppingError(error51)) throw error51;
|
|
49126
|
+
}
|
|
49127
|
+
if (response?.available) return { kind: "reused", result: response.result };
|
|
49128
|
+
if (response?.reason === "database-mismatch") {
|
|
49129
|
+
throw new RvwError(
|
|
49130
|
+
"AGENT_SOCKET_UNAVAILABLE",
|
|
49131
|
+
"\u8D77\u52D5\u4E2D\u306Ervw runtime\u304C\u5225\u306Edatabase\u3092\u4F7F\u7528\u3057\u3066\u3044\u307E\u3059\u3002",
|
|
49132
|
+
{ details: response.details }
|
|
49133
|
+
);
|
|
49134
|
+
}
|
|
49135
|
+
await wait(RUNTIME_REUSE_RETRY_MS);
|
|
49136
|
+
} while (now() < deadline);
|
|
49137
|
+
throw new RvwError("PROCESS_TIMEOUT", "\u8D77\u52D5\u4E2D\u306Ervw runtime\u3078\u306E\u63A5\u7D9A\u304C\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8\u3057\u307E\u3057\u305F\u3002", {
|
|
49138
|
+
details: { timeoutMs }
|
|
49139
|
+
});
|
|
49140
|
+
}
|
|
49141
|
+
async function waitForWorkerParentDisconnect() {
|
|
49142
|
+
if (!process.connected) return;
|
|
49143
|
+
await new Promise((resolve) => process.once("disconnect", resolve));
|
|
49144
|
+
}
|
|
49145
|
+
async function runOpenServer(runtimeFactory, reference, port, openAutomatically, useAgentSocket, reuseExisting) {
|
|
49146
|
+
let activeRuntime;
|
|
48325
49147
|
let running;
|
|
48326
49148
|
let agentSocket;
|
|
48327
49149
|
try {
|
|
49150
|
+
if (useAgentSocket) {
|
|
49151
|
+
const databaseFilePath = databasePathConfiguration().filePath;
|
|
49152
|
+
if (reuseExisting) {
|
|
49153
|
+
const startup = await acquireRuntimeOrReuseExisting(
|
|
49154
|
+
runtimeViewerOpenInput(reference, process.cwd(), port),
|
|
49155
|
+
databaseFilePath
|
|
49156
|
+
);
|
|
49157
|
+
if (startup.kind === "reused") {
|
|
49158
|
+
const result = startup.result;
|
|
49159
|
+
process.stdout.write(`rvw: ${result.url}
|
|
49160
|
+
`);
|
|
49161
|
+
if (!openAutomatically) await holdRuntimeViewerLease(result);
|
|
49162
|
+
return;
|
|
49163
|
+
}
|
|
49164
|
+
agentSocket = startup.agentSocket;
|
|
49165
|
+
} else {
|
|
49166
|
+
agentSocket = await startRuntimeAgentSocket(databaseFilePath);
|
|
49167
|
+
if (!agentSocket.owned) {
|
|
49168
|
+
throw new RvwError(
|
|
49169
|
+
"PROCESS_FAILED",
|
|
49170
|
+
"\u540C\u3058database\u306Ervw runtime\u304C\u65E2\u306B\u8D77\u52D5\u4E2D\u306E\u305F\u3081foreground server\u3092\u958B\u59CB\u3067\u304D\u307E\u305B\u3093\u3002",
|
|
49171
|
+
{
|
|
49172
|
+
suggestions: [
|
|
49173
|
+
"\u901A\u5E38\u306Ervw open\u3067\u65E2\u5B58runtime\u3092\u5229\u7528\u3059\u308B\u304B\u3001\u65E2\u5B58runtime\u3092\u505C\u6B62\u3057\u3066\u304B\u3089\u518D\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
49174
|
+
]
|
|
49175
|
+
}
|
|
49176
|
+
);
|
|
49177
|
+
}
|
|
49178
|
+
}
|
|
49179
|
+
}
|
|
49180
|
+
activeRuntime = runtimeFactory();
|
|
48328
49181
|
const opened = await activeRuntime.service.openPullRequest(reference, process.cwd());
|
|
48329
49182
|
running = await startServer(activeRuntime.service, {
|
|
48330
49183
|
port,
|
|
48331
49184
|
staticDirectory: staticDirectory(),
|
|
48332
49185
|
autoCloseWhenNoViewers: openAutomatically
|
|
48333
49186
|
});
|
|
48334
|
-
|
|
49187
|
+
agentSocket?.setHandler(createRuntimeAgentSocketHandler(activeRuntime, running));
|
|
48335
49188
|
const url2 = new URL(running.origin);
|
|
48336
49189
|
url2.searchParams.set("pullRequestId", opened.pullRequest.id);
|
|
48337
49190
|
process.stdout.write(`rvw: ${url2.toString()}
|
|
@@ -48342,31 +49195,38 @@ async function runOpenServer(activeRuntime, reference, port, openAutomatically,
|
|
|
48342
49195
|
process.stdout.write("rvw: viewer\u3092\u9589\u3058\u305F\u305F\u3081server\u3092\u505C\u6B62\u3057\u307E\u3059\u3002\n");
|
|
48343
49196
|
}
|
|
48344
49197
|
} finally {
|
|
48345
|
-
|
|
48346
|
-
await agentSocket?.close();
|
|
48347
|
-
} finally {
|
|
48348
|
-
try {
|
|
48349
|
-
await running?.close();
|
|
48350
|
-
} finally {
|
|
48351
|
-
activeRuntime.close();
|
|
48352
|
-
}
|
|
48353
|
-
}
|
|
49198
|
+
await closeOwnedRuntime(agentSocket, running, activeRuntime);
|
|
48354
49199
|
}
|
|
48355
49200
|
}
|
|
48356
|
-
async function runOpenWorker(
|
|
49201
|
+
async function runOpenWorker(runtimeFactory, reference, port) {
|
|
49202
|
+
let activeRuntime;
|
|
48357
49203
|
let running;
|
|
48358
49204
|
let agentSocket;
|
|
48359
49205
|
try {
|
|
48360
49206
|
if (!process.send || !process.connected) {
|
|
48361
49207
|
throw new RvwError("INVALID_INPUT", "\u5185\u90E8viewer worker\u306F\u89AACLI\u304B\u3089\u8D77\u52D5\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
48362
49208
|
}
|
|
49209
|
+
const databaseFilePath = databasePathConfiguration().filePath;
|
|
49210
|
+
const startup = await acquireRuntimeOrReuseExisting(
|
|
49211
|
+
runtimeViewerOpenInput(reference, process.cwd(), port),
|
|
49212
|
+
databaseFilePath
|
|
49213
|
+
);
|
|
49214
|
+
if (startup.kind === "reused") {
|
|
49215
|
+
const result = startup.result;
|
|
49216
|
+
if (!await sendOpenWorkerMessage({ type: "ready", url: result.url })) return;
|
|
49217
|
+
if (!await sendOpenWorkerMessage({ type: "viewer-connected" })) return;
|
|
49218
|
+
await waitForWorkerParentDisconnect();
|
|
49219
|
+
return;
|
|
49220
|
+
}
|
|
49221
|
+
agentSocket = startup.agentSocket;
|
|
49222
|
+
activeRuntime = runtimeFactory();
|
|
48363
49223
|
const opened = await activeRuntime.service.openPullRequest(reference, process.cwd());
|
|
48364
49224
|
running = await startServer(activeRuntime.service, {
|
|
48365
49225
|
port,
|
|
48366
49226
|
staticDirectory: staticDirectory(),
|
|
48367
49227
|
autoCloseWhenNoViewers: true
|
|
48368
49228
|
});
|
|
48369
|
-
agentSocket
|
|
49229
|
+
agentSocket.setHandler(createRuntimeAgentSocketHandler(activeRuntime, running));
|
|
48370
49230
|
const url2 = new URL(running.origin);
|
|
48371
49231
|
url2.searchParams.set("pullRequestId", opened.pullRequest.id);
|
|
48372
49232
|
if (!await sendOpenWorkerMessage({ type: "ready", url: url2.toString() })) return;
|
|
@@ -48386,15 +49246,7 @@ async function runOpenWorker(activeRuntime, reference, port) {
|
|
|
48386
49246
|
await sendOpenWorkerMessage({ type: "viewer-connected" });
|
|
48387
49247
|
await waitForServerShutdown(running.allViewersClosed);
|
|
48388
49248
|
} finally {
|
|
48389
|
-
|
|
48390
|
-
await agentSocket?.close();
|
|
48391
|
-
} finally {
|
|
48392
|
-
try {
|
|
48393
|
-
await running?.close();
|
|
48394
|
-
} finally {
|
|
48395
|
-
activeRuntime.close();
|
|
48396
|
-
}
|
|
48397
|
-
}
|
|
49249
|
+
await closeOwnedRuntime(agentSocket, running, activeRuntime);
|
|
48398
49250
|
}
|
|
48399
49251
|
}
|
|
48400
49252
|
var defaultRuntimeFactory = () => createRuntime();
|
|
@@ -48495,12 +49347,19 @@ function createProgram(runtimeFactory = defaultRuntimeFactory) {
|
|
|
48495
49347
|
`);
|
|
48496
49348
|
return;
|
|
48497
49349
|
}
|
|
48498
|
-
await runOpenServer(
|
|
49350
|
+
await runOpenServer(
|
|
49351
|
+
getRuntime,
|
|
49352
|
+
reference,
|
|
49353
|
+
options.port,
|
|
49354
|
+
options.open,
|
|
49355
|
+
useAgentSocket,
|
|
49356
|
+
!options.foreground
|
|
49357
|
+
);
|
|
48499
49358
|
}
|
|
48500
49359
|
);
|
|
48501
49360
|
program2.command("__open-worker", { hidden: true }).option("--reference <pull-request>").requiredOption("--port <port>", "listen port", parsePort).action(async (options) => {
|
|
48502
49361
|
try {
|
|
48503
|
-
await runOpenWorker(getRuntime
|
|
49362
|
+
await runOpenWorker(getRuntime, options.reference, options.port);
|
|
48504
49363
|
} catch (error51) {
|
|
48505
49364
|
const rvwError = asRvwError(error51);
|
|
48506
49365
|
const sent = await sendOpenWorkerMessage({
|
|
@@ -48861,8 +49720,12 @@ if (bundledCli || process.argv[1] && import.meta.url === pathToFileURL(process.a
|
|
|
48861
49720
|
await runCli();
|
|
48862
49721
|
}
|
|
48863
49722
|
export {
|
|
49723
|
+
acquireRuntimeOrReuseExisting,
|
|
49724
|
+
closeOwnedRuntime,
|
|
48864
49725
|
completeBackgroundOpen,
|
|
48865
49726
|
createProgram,
|
|
49727
|
+
createRuntimeAgentSocketHandler,
|
|
49728
|
+
holdRuntimeViewerLease,
|
|
48866
49729
|
runCli,
|
|
48867
49730
|
startBackgroundOpen,
|
|
48868
49731
|
waitForServerShutdown
|