@a9n-shoji/rvw 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +19 -7
- package/dist/cli.mjs +701 -87
- package/dist/cli.mjs.map +4 -4
- package/dist/web/assets/{DocumentViewer-DtusMl0r.js → DocumentViewer-C7UMfzam.js} +1 -1
- package/dist/web/assets/{MarkdownTable-BjwiOHQe.js → MarkdownTable-Dg8UkuDK.js} +1 -1
- package/dist/web/assets/{WalkthroughViewer-BNwKsKzk.js → WalkthroughViewer-BvS7o2T0.js} +1 -1
- package/dist/web/assets/{abnfDiagram-N423BO3Z-DtH8B7Z7.js → abnfDiagram-N423BO3Z-C2idvncb.js} +1 -1
- package/dist/web/assets/architecture-TIHT7OUA-C7fqtQhb.js +1 -0
- package/dist/web/assets/{architectureDiagram-T3A2C74G-5Fq3Xylv.js → architectureDiagram-T3A2C74G-Cdm5LY27.js} +1 -1
- package/dist/web/assets/{blockDiagram-VBNYF7ZC-BBG7PXeg.js → blockDiagram-VBNYF7ZC-C77pTjUb.js} +1 -1
- package/dist/web/assets/{c4Diagram-5PPSVZJV-oLErQeqr.js → c4Diagram-5PPSVZJV-DGHS-vVy.js} +1 -1
- package/dist/web/assets/channel-DwAsM5u1.js +1 -0
- package/dist/web/assets/{chunk-2GRJ4B5K-Bknsyt9u.js → chunk-2GRJ4B5K-DeUANCIz.js} +1 -1
- package/dist/web/assets/{chunk-4I5QYGJK-D-Icvgxq.js → chunk-4I5QYGJK-CMh2oglh.js} +1 -1
- package/dist/web/assets/{chunk-5RXB4S5H-B1iIyQwd.js → chunk-5RXB4S5H-DKTEiVyP.js} +1 -1
- package/dist/web/assets/{chunk-6Q2QTUOP-C09OFw2-.js → chunk-6Q2QTUOP-CcgtbZZN.js} +1 -1
- package/dist/web/assets/{chunk-7Z6QIM7H-BqCAUqX5.js → chunk-7Z6QIM7H-ktwy8mS7.js} +1 -1
- package/dist/web/assets/{chunk-GF5L2VYU-BHy3jGGE.js → chunk-GF5L2VYU-C3sn41mA.js} +1 -1
- package/dist/web/assets/{chunk-I66GZJ75-BBhE3jWF.js → chunk-I66GZJ75-PkPnHXQJ.js} +1 -1
- package/dist/web/assets/{chunk-JQJVKLGR-DNslGDt7.js → chunk-JQJVKLGR-C7Y_Zm_L.js} +1 -1
- package/dist/web/assets/{chunk-KBJHAD2P-J7tWEBhK.js → chunk-KBJHAD2P-CPGb1KEF.js} +1 -1
- package/dist/web/assets/{chunk-NSK5VX7P-retcSoJp.js → chunk-NSK5VX7P-CiYrTyo0.js} +1 -1
- package/dist/web/assets/{chunk-QR6OTTB3-DvFlp4db.js → chunk-QR6OTTB3-Cxc4CBz3.js} +1 -1
- package/dist/web/assets/{chunk-UBXNYLIW-gyX_iwb1.js → chunk-UBXNYLIW-Cu8_QUds.js} +1 -1
- package/dist/web/assets/{chunk-W5SLKNZC-BGNgHuYL.js → chunk-W5SLKNZC-xEW_C207.js} +1 -1
- package/dist/web/assets/{chunk-WRU74C26-66KXN6Rn.js → chunk-WRU74C26-lur1bNcP.js} +1 -1
- package/dist/web/assets/classDiagram-JCYQIIEL-ZOHoHid8.js +1 -0
- package/dist/web/assets/classDiagram-v2-OCEON4UE-ZOHoHid8.js +1 -0
- package/dist/web/assets/{cynefin-VYW2F7L2-Dj_jqvQa.js → cynefin-VYW2F7L2-D8ja_01T.js} +1 -1
- package/dist/web/assets/{cynefinDiagram-MW4NZA55-DSnUS3JS.js → cynefinDiagram-MW4NZA55-DRefzYPy.js} +1 -1
- package/dist/web/assets/{dagre-VZM6K2ZE-BTedug-5.js → dagre-VZM6K2ZE-DzKymXhT.js} +1 -1
- package/dist/web/assets/{diagram-7IWD3JNH-kSc1kTCk.js → diagram-7IWD3JNH-B1TUtKVL.js} +1 -1
- package/dist/web/assets/{diagram-B4RE2ZJO-DNtXohxd.js → diagram-B4RE2ZJO-DQ7yWH6C.js} +1 -1
- package/dist/web/assets/{diagram-LBJQPF4R-CVD-8DKW.js → diagram-LBJQPF4R-h5ld83dF.js} +1 -1
- package/dist/web/assets/{diagram-Q27KOJAE-DBEnUsLJ.js → diagram-Q27KOJAE-CQyWB8j1.js} +1 -1
- package/dist/web/assets/{diagram-UB23O5K3-DiPHfrk7.js → diagram-UB23O5K3-SmscW8SS.js} +1 -1
- package/dist/web/assets/{ebnfDiagram-BXEA7PRR-CE06v37i.js → ebnfDiagram-BXEA7PRR-B6Uv9Fga.js} +1 -1
- package/dist/web/assets/{erDiagram-JOGREHBK-jm3RTuJX.js → erDiagram-JOGREHBK-DlhKVbK5.js} +1 -1
- package/dist/web/assets/eventmodeling-45OFAUF4-hg8ilqKd.js +1 -0
- package/dist/web/assets/flowDiagram-UKHOOZJN-DlU6Mvry.js +1 -0
- package/dist/web/assets/{ganttDiagram-PKOTCBZU--GwSY0BM.js → ganttDiagram-PKOTCBZU-Buwx6kT-.js} +1 -1
- package/dist/web/assets/{gitGraph-TEB2WS4Q-C6oA29oA.js → gitGraph-TEB2WS4Q-DcKoIebc.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-DS77QQ5N-DR1mGQ6a.js → gitGraphDiagram-DS77QQ5N-6hyOioar.js} +1 -1
- package/dist/web/assets/index-CLhFOtpL.css +1 -0
- package/dist/web/assets/index-DYmdeW10.js +384 -0
- package/dist/web/assets/{info-DKCQHKI2-BT4oYSnk.js → info-DKCQHKI2-BTrntoWR.js} +1 -1
- package/dist/web/assets/{infoDiagram-6WML65LV-D0mnXRu0.js → infoDiagram-6WML65LV-C9vEklZc.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-WSZJBQD7-ErnJ_7Sr.js → ishikawaDiagram-WSZJBQD7-u7_elIzl.js} +1 -1
- package/dist/web/assets/{journeyDiagram-NVQOT4AX-CWvooGdp.js → journeyDiagram-NVQOT4AX-C2jFr8oy.js} +1 -1
- package/dist/web/assets/{kanban-definition-27J2QSJJ-DsIS6ipP.js → kanban-definition-27J2QSJJ-D-7UHdx4.js} +1 -1
- package/dist/web/assets/{line-DCcVjraC.js → line-CQAM_baC.js} +1 -1
- package/dist/web/assets/{mermaid-parser.core-BmDn4VB6.js → mermaid-parser.core-D2z7ZOcE.js} +3 -3
- package/dist/web/assets/{mermaid.core-Cus_gjGs.js → mermaid.core-d5lQFkUm.js} +4 -4
- package/dist/web/assets/{mindmap-definition-FAOFIHXS-DdsB9lmP.js → mindmap-definition-FAOFIHXS-tXNzs65p.js} +1 -1
- package/dist/web/assets/{packet-7NZHBO7P-BXuujfeh.js → packet-7NZHBO7P-Ck4WifuO.js} +1 -1
- package/dist/web/assets/{pegDiagram-VL7TDLO6-CBF6Uic6.js → pegDiagram-VL7TDLO6-CI2wa80w.js} +1 -1
- package/dist/web/assets/{pie-RZYD4A2V-DgssvIaB.js → pie-RZYD4A2V-HqKGJX8R.js} +1 -1
- package/dist/web/assets/{pieDiagram-7S7Q4E2Y-DejhR8Wh.js → pieDiagram-7S7Q4E2Y-DiANc3xh.js} +1 -1
- package/dist/web/assets/{quadrantDiagram-CIZ2JOQS-CryFsz7r.js → quadrantDiagram-CIZ2JOQS-Ck1WL56V.js} +1 -1
- package/dist/web/assets/{radar-I7S5WNFK-CoiIzjHC.js → radar-I7S5WNFK-BGZ0ArkI.js} +1 -1
- package/dist/web/assets/{railroad-3IZDKUUU-CWq6IkAh.js → railroad-3IZDKUUU-CG80mKUm.js} +1 -1
- package/dist/web/assets/railroad-abnf-AHOZXSZD-siyTaNqs.js +1 -0
- package/dist/web/assets/railroad-ebnf-EBAXGLYW-CXsuiW_x.js +1 -0
- package/dist/web/assets/railroad-peg-LSFZ7HO6-2Zrn2h_2.js +1 -0
- package/dist/web/assets/{railroadDiagram-AXF67PYL-DkePHtcR.js → railroadDiagram-AXF67PYL-DqLD6_Ag.js} +1 -1
- package/dist/web/assets/{requirementDiagram-LRYGKXZP-D2-9KlK1.js → requirementDiagram-LRYGKXZP-C-GtPNYS.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-W5VNT64P-DSOFAzno.js → sankeyDiagram-W5VNT64P-DiFurH1m.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-SI44F4Z6-BHEKSYJt.js → sequenceDiagram-SI44F4Z6-BBJvY7He.js} +1 -1
- package/dist/web/assets/{stateDiagram-OKZ733FA-f1GttDrB.js → stateDiagram-OKZ733FA-CJJJoWYF.js} +1 -1
- package/dist/web/assets/stateDiagram-v2-UEYNNEHI-Cwihtgsj.js +1 -0
- package/dist/web/assets/{swimlanes-SLNWSIFB-Dx7QlDaA.js → swimlanes-SLNWSIFB-DDD-kqF3.js} +1 -1
- package/dist/web/assets/swimlanesDiagram-ULZ7WXOC-CthM5wkr.js +8 -0
- package/dist/web/assets/{timeline-definition-Z64GVDOM-C7eeBnPC.js → timeline-definition-Z64GVDOM-CPtTrFUL.js} +1 -1
- package/dist/web/assets/{treeView-QDETBFTQ-BPsqqMsK.js → treeView-QDETBFTQ-CXpMsauD.js} +1 -1
- package/dist/web/assets/{treemap-6X3UGDF4-CmBU76N7.js → treemap-6X3UGDF4-DODWUMCI.js} +1 -1
- package/dist/web/assets/{vennDiagram-T6HMQDX7-DTIq1ec9.js → vennDiagram-T6HMQDX7-BjWQrcS4.js} +1 -1
- package/dist/web/assets/{wardley-OPB4EBWU-DLOnGzPl.js → wardley-OPB4EBWU-HV6ftDhi.js} +1 -1
- package/dist/web/assets/{wardleyDiagram-T6FBY63Y-BmzhEoo_.js → wardleyDiagram-T6FBY63Y-DHLZ0oPi.js} +1 -1
- package/dist/web/assets/{xychartDiagram-ELKLHX3M-CcCGC0u-.js → xychartDiagram-ELKLHX3M-CEJ_HkG9.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/architecture-TIHT7OUA-P_K7H_mW.js +0 -1
- 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/eventmodeling-45OFAUF4-C344zcDl.js +0 -1
- package/dist/web/assets/flowDiagram-UKHOOZJN-BAHsb6fm.js +0 -1
- package/dist/web/assets/index-BiPhui1B.js +0 -384
- package/dist/web/assets/index-CHlqmhif.css +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/stateDiagram-v2-UEYNNEHI-CEn2YfQh.js +0 -1
- package/dist/web/assets/swimlanesDiagram-ULZ7WXOC-CX2pXGLK.js +0 -8
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.1";
|
|
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;
|
|
@@ -20643,6 +20670,10 @@ var ghPullRequestSchema = external_exports.object({
|
|
|
20643
20670
|
headRefOid: external_exports.string().regex(GIT_OBJECT_ID_PATTERN),
|
|
20644
20671
|
createdAt: external_exports.string()
|
|
20645
20672
|
});
|
|
20673
|
+
var ghPullRequestStatusSchema = external_exports.object({
|
|
20674
|
+
state: external_exports.enum(["OPEN", "CLOSED", "MERGED"]),
|
|
20675
|
+
isDraft: external_exports.boolean()
|
|
20676
|
+
});
|
|
20646
20677
|
function parsePullRequestUrl(url2) {
|
|
20647
20678
|
const match2 = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)(?:\/.*)?$/.exec(url2);
|
|
20648
20679
|
if (!match2?.[1] || !match2[2] || !match2[3]) {
|
|
@@ -20663,7 +20694,7 @@ var GitHubClient = class {
|
|
|
20663
20694
|
return { version: version2.split("\n")[0] ?? version2, authenticated: auth.exitCode === 0 };
|
|
20664
20695
|
}
|
|
20665
20696
|
async assertAuthenticated() {
|
|
20666
|
-
const status = await
|
|
20697
|
+
const status = await this.processRunner("gh", ["auth", "status", "--hostname", "github.com"], {
|
|
20667
20698
|
allowExitCodes: [1]
|
|
20668
20699
|
});
|
|
20669
20700
|
if (status.exitCode !== 0) {
|
|
@@ -20672,6 +20703,77 @@ var GitHubClient = class {
|
|
|
20672
20703
|
});
|
|
20673
20704
|
}
|
|
20674
20705
|
}
|
|
20706
|
+
async getPullRequestStatus(reference) {
|
|
20707
|
+
let output;
|
|
20708
|
+
try {
|
|
20709
|
+
const result = await this.processRunner(
|
|
20710
|
+
"gh",
|
|
20711
|
+
["pr", "view", reference, "--json", "state,isDraft"],
|
|
20712
|
+
{ timeoutMs: 6e4 }
|
|
20713
|
+
);
|
|
20714
|
+
output = result.stdout.toString("utf8").trimEnd();
|
|
20715
|
+
} catch (error51) {
|
|
20716
|
+
if (error51 instanceof RvwError && error51.code === "PROCESS_FAILED") {
|
|
20717
|
+
throw new RvwError("GITHUB_ERROR", "Pull Request\u72B6\u614B\u3092GitHub\u304B\u3089\u53D6\u5F97\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002", {
|
|
20718
|
+
cause: error51,
|
|
20719
|
+
details: error51.details,
|
|
20720
|
+
suggestions: ["PR URL\u3068gh\u8A8D\u8A3C\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002"]
|
|
20721
|
+
});
|
|
20722
|
+
}
|
|
20723
|
+
throw error51;
|
|
20724
|
+
}
|
|
20725
|
+
let decoded;
|
|
20726
|
+
try {
|
|
20727
|
+
decoded = JSON.parse(output);
|
|
20728
|
+
} catch (error51) {
|
|
20729
|
+
throw new RvwError("GITHUB_ERROR", "GitHub CLI\u306EPull Request\u72B6\u614B\u5FDC\u7B54\u304C\u4E0D\u6B63\u3067\u3059\u3002", {
|
|
20730
|
+
cause: error51
|
|
20731
|
+
});
|
|
20732
|
+
}
|
|
20733
|
+
const parsed = ghPullRequestStatusSchema.safeParse(decoded);
|
|
20734
|
+
if (!parsed.success) {
|
|
20735
|
+
throw new RvwError("GITHUB_ERROR", "GitHub CLI\u306EPull Request\u72B6\u614B\u5FDC\u7B54\u304C\u4E0D\u6B63\u3067\u3059\u3002", {
|
|
20736
|
+
details: parsed.error.flatten()
|
|
20737
|
+
});
|
|
20738
|
+
}
|
|
20739
|
+
return parsed.data;
|
|
20740
|
+
}
|
|
20741
|
+
async getPullRequestStatuses(references) {
|
|
20742
|
+
if (references.length === 0) return [];
|
|
20743
|
+
await this.assertAuthenticated();
|
|
20744
|
+
const outcomes = Array.from(
|
|
20745
|
+
{ length: references.length },
|
|
20746
|
+
() => void 0
|
|
20747
|
+
);
|
|
20748
|
+
let nextIndex = 0;
|
|
20749
|
+
const workerCount = Math.min(4, references.length);
|
|
20750
|
+
await Promise.all(
|
|
20751
|
+
Array.from({ length: workerCount }, async () => {
|
|
20752
|
+
while (nextIndex < references.length) {
|
|
20753
|
+
const index2 = nextIndex;
|
|
20754
|
+
nextIndex += 1;
|
|
20755
|
+
const reference = references[index2];
|
|
20756
|
+
if (!reference) continue;
|
|
20757
|
+
try {
|
|
20758
|
+
outcomes[index2] = {
|
|
20759
|
+
status: "fulfilled",
|
|
20760
|
+
value: await this.getPullRequestStatus(reference)
|
|
20761
|
+
};
|
|
20762
|
+
} catch (error51) {
|
|
20763
|
+
outcomes[index2] = { status: "rejected", error: error51 };
|
|
20764
|
+
}
|
|
20765
|
+
}
|
|
20766
|
+
})
|
|
20767
|
+
);
|
|
20768
|
+
return outcomes.map((outcome) => {
|
|
20769
|
+
if (!outcome) {
|
|
20770
|
+
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", {
|
|
20771
|
+
status: 500
|
|
20772
|
+
});
|
|
20773
|
+
}
|
|
20774
|
+
return outcome;
|
|
20775
|
+
});
|
|
20776
|
+
}
|
|
20675
20777
|
async getPullRequest(reference, cwd, options = {}) {
|
|
20676
20778
|
await this.assertAuthenticated();
|
|
20677
20779
|
const fields = [
|
|
@@ -41282,6 +41384,42 @@ var RvwService = class {
|
|
|
41282
41384
|
}
|
|
41283
41385
|
};
|
|
41284
41386
|
}
|
|
41387
|
+
async refreshPullRequestStatuses() {
|
|
41388
|
+
const pullRequests = this.database.listPullRequestsNeedingStatusRefresh();
|
|
41389
|
+
if (pullRequests.length === 0) {
|
|
41390
|
+
return { attempted: 0, updated: 0, failures: [] };
|
|
41391
|
+
}
|
|
41392
|
+
const outcomes = await this.github.getPullRequestStatuses(
|
|
41393
|
+
pullRequests.map((pullRequest) => pullRequest.url)
|
|
41394
|
+
);
|
|
41395
|
+
if (outcomes.length !== pullRequests.length) {
|
|
41396
|
+
throw new RvwError("GITHUB_ERROR", "Pull Request\u72B6\u614B\u306E\u4E00\u62EC\u53D6\u5F97\u4EF6\u6570\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002", {
|
|
41397
|
+
status: 502
|
|
41398
|
+
});
|
|
41399
|
+
}
|
|
41400
|
+
const successful = outcomes.flatMap((outcome, index2) => {
|
|
41401
|
+
const pullRequest = pullRequests[index2];
|
|
41402
|
+
return outcome.status === "fulfilled" && pullRequest ? [{ pullRequestId: pullRequest.id, ...outcome.value }] : [];
|
|
41403
|
+
});
|
|
41404
|
+
this.database.updatePullRequestGitHubStatuses(successful);
|
|
41405
|
+
const failures = outcomes.flatMap((outcome, index2) => {
|
|
41406
|
+
const pullRequest = pullRequests[index2];
|
|
41407
|
+
return outcome.status === "rejected" && pullRequest ? [
|
|
41408
|
+
{
|
|
41409
|
+
pullRequestId: pullRequest.id,
|
|
41410
|
+
owner: pullRequest.owner,
|
|
41411
|
+
repository: pullRequest.repository,
|
|
41412
|
+
number: pullRequest.number,
|
|
41413
|
+
error: asRvwError(outcome.error).toJSON()
|
|
41414
|
+
}
|
|
41415
|
+
] : [];
|
|
41416
|
+
});
|
|
41417
|
+
return {
|
|
41418
|
+
attempted: pullRequests.length,
|
|
41419
|
+
updated: successful.length,
|
|
41420
|
+
failures
|
|
41421
|
+
};
|
|
41422
|
+
}
|
|
41285
41423
|
resolveStoredPullRequest(reference) {
|
|
41286
41424
|
if (/^https:\/\/github\.com\//.test(reference)) {
|
|
41287
41425
|
const parsed = parsePullRequestUrl(reference);
|
|
@@ -42639,6 +42777,9 @@ var SkillInstaller = class {
|
|
|
42639
42777
|
}
|
|
42640
42778
|
};
|
|
42641
42779
|
|
|
42780
|
+
// src/server/start-server.ts
|
|
42781
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
42782
|
+
|
|
42642
42783
|
// node_modules/.pnpm/@hono+node-server@2.1.0_hono@4.13.1/node_modules/@hono/node-server/dist/constants-BLSFu_RU.mjs
|
|
42643
42784
|
var X_ALREADY_SENT = "x-hono-already-sent";
|
|
42644
42785
|
|
|
@@ -46532,7 +46673,11 @@ function createApp(service, options) {
|
|
|
46532
46673
|
app.get("/api/meta/change-sequence", (context) => {
|
|
46533
46674
|
const rawViewerId = context.req.header(VIEWER_ID_HEADER);
|
|
46534
46675
|
if (rawViewerId !== void 0) {
|
|
46535
|
-
|
|
46676
|
+
const rawViewerLease = context.req.header(VIEWER_OPEN_LEASE_HEADER);
|
|
46677
|
+
options.viewerLifecycle?.heartbeat(
|
|
46678
|
+
viewerIdSchema.parse(rawViewerId),
|
|
46679
|
+
rawViewerLease === void 0 ? void 0 : viewerIdSchema.parse(rawViewerLease)
|
|
46680
|
+
);
|
|
46536
46681
|
}
|
|
46537
46682
|
return context.json({ ok: true, changeSequence: service.database.getChangeSequence() });
|
|
46538
46683
|
});
|
|
@@ -46560,6 +46705,10 @@ function createApp(service, options) {
|
|
|
46560
46705
|
});
|
|
46561
46706
|
return context.json({ ok: true, ...service.listPullRequests(query) });
|
|
46562
46707
|
});
|
|
46708
|
+
app.post(
|
|
46709
|
+
"/api/pull-requests/refresh-statuses",
|
|
46710
|
+
async (context) => context.json({ ok: true, ...await service.refreshPullRequestStatuses() })
|
|
46711
|
+
);
|
|
46563
46712
|
app.get(
|
|
46564
46713
|
"/api/pull-requests/:id",
|
|
46565
46714
|
async (context) => context.json({ ok: true, ...await service.getPullRequestView(context.req.param("id")) })
|
|
@@ -46837,14 +46986,17 @@ var ViewerLifecycle = class {
|
|
|
46837
46986
|
constructor(options) {
|
|
46838
46987
|
this.options = options;
|
|
46839
46988
|
this.leaseTimeoutMs = options.leaseTimeoutMs ?? DEFAULT_VIEWER_LEASE_TIMEOUT_MS;
|
|
46989
|
+
this.startupTimeoutMs = options.startupTimeoutMs ?? DEFAULT_VIEWER_STARTUP_TIMEOUT_MS;
|
|
46840
46990
|
this.closeGraceMs = options.closeGraceMs ?? DEFAULT_VIEWER_CLOSE_GRACE_MS;
|
|
46841
46991
|
this.timerLatenessToleranceMs = options.timerLatenessToleranceMs ?? DEFAULT_TIMER_LATENESS_TOLERANCE_MS;
|
|
46842
46992
|
}
|
|
46843
46993
|
options;
|
|
46844
46994
|
viewers = /* @__PURE__ */ new Map();
|
|
46995
|
+
pendingViewers = /* @__PURE__ */ new Map();
|
|
46845
46996
|
// A poll already in flight can arrive after its pagehide release. Keep that document closed.
|
|
46846
46997
|
releasedViewers = /* @__PURE__ */ new Set();
|
|
46847
46998
|
leaseTimeoutMs;
|
|
46999
|
+
startupTimeoutMs;
|
|
46848
47000
|
closeGraceMs;
|
|
46849
47001
|
timerLatenessToleranceMs;
|
|
46850
47002
|
timer = null;
|
|
@@ -46853,35 +47005,72 @@ var ViewerLifecycle = class {
|
|
|
46853
47005
|
get activeViewerCount() {
|
|
46854
47006
|
return this.viewers.size;
|
|
46855
47007
|
}
|
|
46856
|
-
|
|
47008
|
+
get pendingViewerCount() {
|
|
47009
|
+
return this.pendingViewers.size;
|
|
47010
|
+
}
|
|
47011
|
+
reserveViewer(leaseId) {
|
|
47012
|
+
if (this.stopped) return false;
|
|
47013
|
+
this.pendingViewers.set(leaseId, { phase: "opening" });
|
|
47014
|
+
this.scheduleActivityCheck();
|
|
47015
|
+
return true;
|
|
47016
|
+
}
|
|
47017
|
+
armViewerReservation(leaseId) {
|
|
47018
|
+
if (this.stopped || !this.pendingViewers.has(leaseId)) return false;
|
|
47019
|
+
this.pendingViewers.set(leaseId, {
|
|
47020
|
+
phase: "startup",
|
|
47021
|
+
deadline: Date.now() + this.startupTimeoutMs,
|
|
47022
|
+
timeoutMs: this.startupTimeoutMs
|
|
47023
|
+
});
|
|
47024
|
+
this.scheduleActivityCheck();
|
|
47025
|
+
return true;
|
|
47026
|
+
}
|
|
47027
|
+
cancelViewerReservation(leaseId) {
|
|
47028
|
+
if (this.stopped || !this.pendingViewers.delete(leaseId)) return;
|
|
47029
|
+
this.scheduleNext();
|
|
47030
|
+
}
|
|
47031
|
+
heartbeat(viewerId, pendingLeaseId) {
|
|
46857
47032
|
if (this.stopped || this.releasedViewers.has(viewerId)) return;
|
|
47033
|
+
if (pendingLeaseId !== void 0) this.pendingViewers.delete(pendingLeaseId);
|
|
46858
47034
|
if (!this.viewerHasConnected) {
|
|
46859
47035
|
this.viewerHasConnected = true;
|
|
46860
47036
|
this.options.onFirstViewerConnected?.();
|
|
46861
47037
|
}
|
|
46862
47038
|
this.viewers.set(viewerId, Date.now());
|
|
46863
|
-
this.
|
|
47039
|
+
this.scheduleActivityCheck();
|
|
46864
47040
|
}
|
|
46865
47041
|
release(viewerId) {
|
|
46866
47042
|
if (this.stopped) return;
|
|
46867
47043
|
this.releasedViewers.add(viewerId);
|
|
46868
47044
|
if (!this.viewers.delete(viewerId)) return;
|
|
46869
|
-
|
|
46870
|
-
else this.scheduleLeaseCheck();
|
|
47045
|
+
this.scheduleNext();
|
|
46871
47046
|
}
|
|
46872
47047
|
close() {
|
|
46873
47048
|
this.stopped = true;
|
|
46874
47049
|
this.clearTimer();
|
|
46875
47050
|
this.viewers.clear();
|
|
47051
|
+
this.pendingViewers.clear();
|
|
46876
47052
|
this.releasedViewers.clear();
|
|
46877
47053
|
}
|
|
46878
|
-
|
|
46879
|
-
if (this.
|
|
46880
|
-
|
|
46881
|
-
|
|
47054
|
+
scheduleNext() {
|
|
47055
|
+
if (this.viewers.size > 0 || this.pendingViewers.size > 0) this.scheduleActivityCheck();
|
|
47056
|
+
else this.scheduleEmptyShutdown();
|
|
47057
|
+
}
|
|
47058
|
+
scheduleActivityCheck() {
|
|
47059
|
+
if (this.stopped) return;
|
|
47060
|
+
const deadlines = [
|
|
47061
|
+
...Array.from(this.viewers.values(), (heartbeat) => heartbeat + this.leaseTimeoutMs),
|
|
47062
|
+
...Array.from(this.pendingViewers.values()).filter(
|
|
47063
|
+
(pending) => pending.phase === "startup"
|
|
47064
|
+
).map((pending) => pending.deadline)
|
|
47065
|
+
];
|
|
47066
|
+
if (deadlines.length === 0) {
|
|
47067
|
+
this.clearTimer();
|
|
47068
|
+
return;
|
|
47069
|
+
}
|
|
47070
|
+
this.schedule("activity", Math.min(...deadlines));
|
|
46882
47071
|
}
|
|
46883
47072
|
scheduleEmptyShutdown() {
|
|
46884
|
-
if (this.stopped || this.viewers.size > 0) return;
|
|
47073
|
+
if (this.stopped || this.viewers.size > 0 || this.pendingViewers.size > 0) return;
|
|
46885
47074
|
this.schedule("empty", Date.now() + this.closeGraceMs);
|
|
46886
47075
|
}
|
|
46887
47076
|
schedule(kind, deadline) {
|
|
@@ -46895,23 +47084,33 @@ var ViewerLifecycle = class {
|
|
|
46895
47084
|
const now = Date.now();
|
|
46896
47085
|
if (now - deadline > this.timerLatenessToleranceMs) {
|
|
46897
47086
|
for (const viewerId of this.viewers.keys()) this.viewers.set(viewerId, now);
|
|
46898
|
-
|
|
46899
|
-
|
|
47087
|
+
for (const [leaseId, pending] of this.pendingViewers) {
|
|
47088
|
+
if (pending.phase !== "startup") continue;
|
|
47089
|
+
this.pendingViewers.set(leaseId, {
|
|
47090
|
+
phase: "startup",
|
|
47091
|
+
deadline: now + pending.timeoutMs,
|
|
47092
|
+
timeoutMs: pending.timeoutMs
|
|
47093
|
+
});
|
|
47094
|
+
}
|
|
47095
|
+
this.scheduleNext();
|
|
46900
47096
|
return;
|
|
46901
47097
|
}
|
|
46902
|
-
if (kind === "
|
|
47098
|
+
if (kind === "activity") {
|
|
46903
47099
|
for (const [viewerId, lastHeartbeat] of this.viewers) {
|
|
46904
47100
|
if (now - lastHeartbeat >= this.leaseTimeoutMs) this.viewers.delete(viewerId);
|
|
46905
47101
|
}
|
|
46906
|
-
|
|
46907
|
-
|
|
47102
|
+
for (const [leaseId, pending] of this.pendingViewers) {
|
|
47103
|
+
if (pending.phase !== "startup") continue;
|
|
47104
|
+
if (now >= pending.deadline) this.pendingViewers.delete(leaseId);
|
|
47105
|
+
}
|
|
47106
|
+
this.scheduleNext();
|
|
46908
47107
|
return;
|
|
46909
47108
|
}
|
|
46910
|
-
if (this.viewers.size === 0) {
|
|
47109
|
+
if (this.viewers.size === 0 && this.pendingViewers.size === 0) {
|
|
46911
47110
|
this.stopped = true;
|
|
46912
47111
|
this.options.onAllViewersClosed();
|
|
46913
47112
|
} else {
|
|
46914
|
-
this.
|
|
47113
|
+
this.scheduleActivityCheck();
|
|
46915
47114
|
}
|
|
46916
47115
|
}
|
|
46917
47116
|
clearTimer() {
|
|
@@ -46921,6 +47120,7 @@ var ViewerLifecycle = class {
|
|
|
46921
47120
|
};
|
|
46922
47121
|
|
|
46923
47122
|
// src/server/start-server.ts
|
|
47123
|
+
var RUNTIME_STOPPING_REASON = "runtime-stopping";
|
|
46924
47124
|
async function startServer(service, options = {}) {
|
|
46925
47125
|
const host = "127.0.0.1";
|
|
46926
47126
|
const security = { expectedHost: null, expectedOrigin: null };
|
|
@@ -46960,6 +47160,33 @@ async function startServer(service, options = {}) {
|
|
|
46960
47160
|
origin,
|
|
46961
47161
|
firstViewerConnected,
|
|
46962
47162
|
allViewersClosed,
|
|
47163
|
+
reserveViewer: () => {
|
|
47164
|
+
if (!viewerLifecycle) return null;
|
|
47165
|
+
const leaseId = randomUUID4();
|
|
47166
|
+
if (!viewerLifecycle.reserveViewer(leaseId)) {
|
|
47167
|
+
throw new RvwError(
|
|
47168
|
+
"PROCESS_FAILED",
|
|
47169
|
+
"rvw runtime\u306F\u505C\u6B62\u51E6\u7406\u4E2D\u306E\u305F\u3081viewer\u3092\u8FFD\u52A0\u3067\u304D\u307E\u305B\u3093\u3002",
|
|
47170
|
+
{
|
|
47171
|
+
details: { reason: RUNTIME_STOPPING_REASON },
|
|
47172
|
+
suggestions: ["rvw open\u3092\u518D\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002"]
|
|
47173
|
+
}
|
|
47174
|
+
);
|
|
47175
|
+
}
|
|
47176
|
+
return leaseId;
|
|
47177
|
+
},
|
|
47178
|
+
armViewerReservation: (leaseId) => {
|
|
47179
|
+
if (!viewerLifecycle || viewerLifecycle.armViewerReservation(leaseId)) return;
|
|
47180
|
+
throw new RvwError(
|
|
47181
|
+
"PROCESS_FAILED",
|
|
47182
|
+
"rvw runtime\u306F\u505C\u6B62\u51E6\u7406\u4E2D\u306E\u305F\u3081viewer\u3092\u8FFD\u52A0\u3067\u304D\u307E\u305B\u3093\u3002",
|
|
47183
|
+
{
|
|
47184
|
+
details: { reason: RUNTIME_STOPPING_REASON },
|
|
47185
|
+
suggestions: ["rvw open\u3092\u518D\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002"]
|
|
47186
|
+
}
|
|
47187
|
+
);
|
|
47188
|
+
},
|
|
47189
|
+
cancelViewerReservation: (leaseId) => viewerLifecycle?.cancelViewerReservation(leaseId),
|
|
46963
47190
|
close: () => closePromise ??= (async () => {
|
|
46964
47191
|
viewerLifecycle?.close();
|
|
46965
47192
|
await new Promise((closeResolve, closeReject) => {
|
|
@@ -46974,7 +47201,7 @@ async function startServer(service, options = {}) {
|
|
|
46974
47201
|
}
|
|
46975
47202
|
|
|
46976
47203
|
// src/server/agent-socket.ts
|
|
46977
|
-
import { createHash as createHash5, randomUUID as
|
|
47204
|
+
import { createHash as createHash5, randomUUID as randomUUID5 } from "node:crypto";
|
|
46978
47205
|
import {
|
|
46979
47206
|
chmodSync as chmodSync2,
|
|
46980
47207
|
existsSync as existsSync5,
|
|
@@ -46990,7 +47217,8 @@ import os4 from "node:os";
|
|
|
46990
47217
|
import path9 from "node:path";
|
|
46991
47218
|
var MAX_CLI_STDIN_BYTES = 40 * 1024 * 1024;
|
|
46992
47219
|
var MAX_AGENT_MESSAGE_BYTES = MAX_CLI_STDIN_BYTES + 64 * 1024;
|
|
46993
|
-
var AGENT_SOCKET_PROTOCOL_VERSION =
|
|
47220
|
+
var AGENT_SOCKET_PROTOCOL_VERSION = 4;
|
|
47221
|
+
var RUNTIME_VIEWER_OPEN_OPERATION = "viewer.open";
|
|
46994
47222
|
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
47223
|
var DEFAULT_CONNECT_TIMEOUT_MS = 2e3;
|
|
46996
47224
|
var DEFAULT_OPERATION_TIMEOUT_MS = 18e4;
|
|
@@ -47003,6 +47231,19 @@ var agentRequestEnvelopeSchema = external_exports.object({
|
|
|
47003
47231
|
input: external_exports.unknown(),
|
|
47004
47232
|
expectedDatabasePath: external_exports.string().min(1).optional()
|
|
47005
47233
|
}).strict();
|
|
47234
|
+
var runtimeViewerOpenInputSchema = external_exports.object({
|
|
47235
|
+
reference: external_exports.string().min(1).optional(),
|
|
47236
|
+
cwd: external_exports.string().min(1),
|
|
47237
|
+
requestedPort: external_exports.number().int().min(0).max(65535)
|
|
47238
|
+
}).strict();
|
|
47239
|
+
var runtimeViewerOpenResultSchema = external_exports.object({
|
|
47240
|
+
url: external_exports.string().url(),
|
|
47241
|
+
origin: external_exports.string().url(),
|
|
47242
|
+
port: external_exports.number().int().min(1).max(65535),
|
|
47243
|
+
pullRequestId: external_exports.string().min(1),
|
|
47244
|
+
ownerPid: external_exports.number().int().positive(),
|
|
47245
|
+
viewerLeaseId: external_exports.uuid().optional()
|
|
47246
|
+
}).strict();
|
|
47006
47247
|
function explicitAgentSocketPath() {
|
|
47007
47248
|
const configuredPath = process.env.RVW_AGENT_SOCKET_PATH;
|
|
47008
47249
|
if (configuredPath === void 0) return null;
|
|
@@ -47058,7 +47299,10 @@ function parseOperationInput(operation, value) {
|
|
|
47058
47299
|
if (!parsed.success) throw invalidSocketInput(parsed.error);
|
|
47059
47300
|
return parsed.data;
|
|
47060
47301
|
}
|
|
47061
|
-
|
|
47302
|
+
function resolveDatabaseIdentity(databaseFilePath) {
|
|
47303
|
+
return databaseFilePath === ":memory:" ? databaseFilePath : path9.resolve(databaseFilePath);
|
|
47304
|
+
}
|
|
47305
|
+
function validateAgentRequest(rawRequest, databaseFilePath) {
|
|
47062
47306
|
const request = parseRequest(rawRequest);
|
|
47063
47307
|
if (request.protocolVersion !== AGENT_SOCKET_PROTOCOL_VERSION) {
|
|
47064
47308
|
throw new RvwError("STALE_PROTOCOL", "Agent socket protocol version\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002", {
|
|
@@ -47069,23 +47313,30 @@ async function dispatchAgentSocketRequest(service, rawRequest) {
|
|
|
47069
47313
|
suggestions: [AGENT_SOCKET_RESTART_SUGGESTION]
|
|
47070
47314
|
});
|
|
47071
47315
|
}
|
|
47072
|
-
if (request.expectedDatabasePath !== void 0 &&
|
|
47316
|
+
if (request.expectedDatabasePath !== void 0 && databaseFilePath !== void 0 && resolveDatabaseIdentity(request.expectedDatabasePath) !== resolveDatabaseIdentity(databaseFilePath)) {
|
|
47073
47317
|
throw new RvwError("DATABASE_ERROR", "Agent socket\u304C\u5225\u306Edatabase\u3092\u4F7F\u7528\u3057\u3066\u3044\u307E\u3059\u3002", {
|
|
47074
47318
|
details: {
|
|
47075
47319
|
agentSocketDatabaseMismatch: true,
|
|
47076
|
-
expectedDatabasePath:
|
|
47077
|
-
actualDatabasePath:
|
|
47320
|
+
expectedDatabasePath: resolveDatabaseIdentity(request.expectedDatabasePath),
|
|
47321
|
+
actualDatabasePath: resolveDatabaseIdentity(databaseFilePath)
|
|
47078
47322
|
}
|
|
47079
47323
|
});
|
|
47080
47324
|
}
|
|
47325
|
+
return request;
|
|
47326
|
+
}
|
|
47327
|
+
function pingResult(databaseFilePath) {
|
|
47328
|
+
return {
|
|
47329
|
+
protocolVersion: AGENT_SOCKET_PROTOCOL_VERSION,
|
|
47330
|
+
databasePath: resolveDatabaseIdentity(databaseFilePath),
|
|
47331
|
+
ownerPid: process.pid
|
|
47332
|
+
};
|
|
47333
|
+
}
|
|
47334
|
+
async function dispatchAgentSocketRequest(service, rawRequest) {
|
|
47335
|
+
const request = validateAgentRequest(rawRequest, service.database?.filePath);
|
|
47081
47336
|
if (request.operation === "ping") {
|
|
47082
47337
|
const ping = external_exports.object({}).strict().safeParse(request.input);
|
|
47083
47338
|
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
|
-
};
|
|
47339
|
+
return pingResult(service.database.filePath);
|
|
47089
47340
|
}
|
|
47090
47341
|
if (!Object.hasOwn(agentCommandInputSchemas, request.operation)) {
|
|
47091
47342
|
throw new RvwError("INVALID_INPUT", `\u672A\u5BFE\u5FDC\u306EAgent socket operation\u3067\u3059: ${request.operation}`);
|
|
@@ -47390,6 +47641,38 @@ async function tryAgentSocketRequest(operation, input, options = {}) {
|
|
|
47390
47641
|
});
|
|
47391
47642
|
});
|
|
47392
47643
|
}
|
|
47644
|
+
async function tryRuntimeViewerOpen(input, databaseFilePath = databasePathConfiguration().filePath, options = {}) {
|
|
47645
|
+
const parsedInput = runtimeViewerOpenInputSchema.safeParse(input);
|
|
47646
|
+
if (!parsedInput.success) throw invalidSocketInput(parsedInput.error);
|
|
47647
|
+
const response = await tryAgentSocketRequest(
|
|
47648
|
+
RUNTIME_VIEWER_OPEN_OPERATION,
|
|
47649
|
+
parsedInput.data,
|
|
47650
|
+
{
|
|
47651
|
+
expectedDatabasePath: databaseFilePath,
|
|
47652
|
+
requireSocket: false,
|
|
47653
|
+
...options
|
|
47654
|
+
}
|
|
47655
|
+
);
|
|
47656
|
+
if (!response.available) return response;
|
|
47657
|
+
const parsedResult = runtimeViewerOpenResultSchema.safeParse(response.result);
|
|
47658
|
+
if (!parsedResult.success) {
|
|
47659
|
+
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", {
|
|
47660
|
+
details: { issues: parsedResult.error.issues },
|
|
47661
|
+
suggestions: [AGENT_SOCKET_RESTART_SUGGESTION]
|
|
47662
|
+
});
|
|
47663
|
+
}
|
|
47664
|
+
return {
|
|
47665
|
+
available: true,
|
|
47666
|
+
result: {
|
|
47667
|
+
url: parsedResult.data.url,
|
|
47668
|
+
origin: parsedResult.data.origin,
|
|
47669
|
+
port: parsedResult.data.port,
|
|
47670
|
+
pullRequestId: parsedResult.data.pullRequestId,
|
|
47671
|
+
ownerPid: parsedResult.data.ownerPid,
|
|
47672
|
+
...parsedResult.data.viewerLeaseId === void 0 ? {} : { viewerLeaseId: parsedResult.data.viewerLeaseId }
|
|
47673
|
+
}
|
|
47674
|
+
};
|
|
47675
|
+
}
|
|
47393
47676
|
async function inspectAgentTransport(databaseFilePath = databasePathConfiguration().filePath) {
|
|
47394
47677
|
const expectedDatabasePath = databaseFilePath === ":memory:" ? databaseFilePath : path9.resolve(databaseFilePath);
|
|
47395
47678
|
const configuredSocketPath = explicitAgentSocketPath();
|
|
@@ -47492,7 +47775,7 @@ function socketOwnerPid(lockPath) {
|
|
|
47492
47775
|
function tryAcquireSocketOwnerLock(socketPath) {
|
|
47493
47776
|
const lockPath = `${socketPath}${OWNER_LOCK_SUFFIX}`;
|
|
47494
47777
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
47495
|
-
const stagingPath = `${lockPath}.${process.pid}.${
|
|
47778
|
+
const stagingPath = `${lockPath}.${process.pid}.${randomUUID5()}.tmp`;
|
|
47496
47779
|
try {
|
|
47497
47780
|
writeFileSync2(stagingPath, `${JSON.stringify({ pid: process.pid })}
|
|
47498
47781
|
`, {
|
|
@@ -47536,7 +47819,7 @@ function releaseSocketOwnerLock(lock) {
|
|
|
47536
47819
|
if (!lock) return;
|
|
47537
47820
|
unlinkIfOwned(lock.path, lock.identity);
|
|
47538
47821
|
}
|
|
47539
|
-
function createAgentServer(
|
|
47822
|
+
function createAgentServer(dispatch) {
|
|
47540
47823
|
const server = net.createServer((socket) => {
|
|
47541
47824
|
const chunks = [];
|
|
47542
47825
|
let bytes = 0;
|
|
@@ -47561,7 +47844,7 @@ function createAgentServer(service) {
|
|
|
47561
47844
|
const request = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
47562
47845
|
response = {
|
|
47563
47846
|
ok: true,
|
|
47564
|
-
result: await
|
|
47847
|
+
result: await dispatch(parseRequest(request))
|
|
47565
47848
|
};
|
|
47566
47849
|
} catch (error51) {
|
|
47567
47850
|
response = { ok: false, error: asRvwError(error51).toJSON() };
|
|
@@ -47589,8 +47872,8 @@ async function listen(server, socketPath) {
|
|
|
47589
47872
|
server.listen(socketPath);
|
|
47590
47873
|
});
|
|
47591
47874
|
}
|
|
47592
|
-
async function
|
|
47593
|
-
const socketPath = agentSocketPath(
|
|
47875
|
+
async function startAgentSocketListener(databaseFilePath, dispatch, options) {
|
|
47876
|
+
const socketPath = agentSocketPath(databaseFilePath);
|
|
47594
47877
|
ensurePrivateSocketDirectory(socketPath);
|
|
47595
47878
|
const retryDelay = options.takeoverRetryMs ?? DEFAULT_TAKEOVER_RETRY_MS;
|
|
47596
47879
|
let server = null;
|
|
@@ -47598,9 +47881,12 @@ async function startAgentSocket(service, options = {}) {
|
|
|
47598
47881
|
let ownerLock = null;
|
|
47599
47882
|
let retryTimer;
|
|
47600
47883
|
let acquisition = null;
|
|
47884
|
+
let listenerDrain = null;
|
|
47885
|
+
let stopPromise = null;
|
|
47886
|
+
let releasePromise = null;
|
|
47601
47887
|
let closed = false;
|
|
47602
47888
|
const scheduleTakeover = () => {
|
|
47603
|
-
if (closed || server || retryTimer) return;
|
|
47889
|
+
if (!options.retryOwnership || closed || server || retryTimer) return;
|
|
47604
47890
|
retryTimer = setTimeout(() => {
|
|
47605
47891
|
retryTimer = void 0;
|
|
47606
47892
|
void acquire().catch(() => scheduleTakeover());
|
|
@@ -47629,7 +47915,7 @@ async function startAgentSocket(service, options = {}) {
|
|
|
47629
47915
|
throw error51;
|
|
47630
47916
|
}
|
|
47631
47917
|
}
|
|
47632
|
-
const candidate = createAgentServer(
|
|
47918
|
+
const candidate = createAgentServer(dispatch);
|
|
47633
47919
|
try {
|
|
47634
47920
|
await listen(candidate, socketPath);
|
|
47635
47921
|
} catch (error51) {
|
|
@@ -47661,12 +47947,16 @@ async function startAgentSocket(service, options = {}) {
|
|
|
47661
47947
|
ownerLock = candidateLock;
|
|
47662
47948
|
candidate.on("error", () => {
|
|
47663
47949
|
if (server !== candidate) return;
|
|
47664
|
-
const failedIdentity = identity;
|
|
47665
|
-
const failedOwnerLock = ownerLock;
|
|
47666
47950
|
server = null;
|
|
47951
|
+
listenerDrain = new Promise((resolve) => candidate.close(() => resolve()));
|
|
47952
|
+
if (!options.retryOwnership) {
|
|
47953
|
+
return;
|
|
47954
|
+
}
|
|
47955
|
+
const failedIdentity = identity;
|
|
47667
47956
|
identity = null;
|
|
47957
|
+
const failedOwnerLock = ownerLock;
|
|
47668
47958
|
ownerLock = null;
|
|
47669
|
-
|
|
47959
|
+
void listenerDrain.then(() => {
|
|
47670
47960
|
unlinkIfOwned(socketPath, failedIdentity);
|
|
47671
47961
|
releaseSocketOwnerLock(failedOwnerLock);
|
|
47672
47962
|
scheduleTakeover();
|
|
@@ -47680,33 +47970,128 @@ async function startAgentSocket(service, options = {}) {
|
|
|
47680
47970
|
}
|
|
47681
47971
|
};
|
|
47682
47972
|
await acquire();
|
|
47683
|
-
|
|
47684
|
-
|
|
47685
|
-
get owned() {
|
|
47686
|
-
return server !== null;
|
|
47687
|
-
},
|
|
47688
|
-
close: async () => {
|
|
47973
|
+
const stopAccepting = async () => {
|
|
47974
|
+
await (stopPromise ??= (async () => {
|
|
47689
47975
|
closed = true;
|
|
47690
47976
|
if (retryTimer) clearTimeout(retryTimer);
|
|
47691
47977
|
await acquisition;
|
|
47978
|
+
if (listenerDrain) await listenerDrain;
|
|
47692
47979
|
const ownedServer = server;
|
|
47693
|
-
const ownedIdentity = identity;
|
|
47694
|
-
const ownedOwnerLock = ownerLock;
|
|
47695
47980
|
server = null;
|
|
47696
|
-
|
|
47697
|
-
|
|
47698
|
-
|
|
47699
|
-
|
|
47700
|
-
|
|
47701
|
-
|
|
47981
|
+
if (!ownedServer) return;
|
|
47982
|
+
listenerDrain = new Promise(
|
|
47983
|
+
(resolve, reject) => ownedServer.close((error51) => error51 ? reject(error51) : resolve())
|
|
47984
|
+
);
|
|
47985
|
+
await listenerDrain;
|
|
47986
|
+
})());
|
|
47987
|
+
};
|
|
47988
|
+
const releaseOwnership = async () => {
|
|
47989
|
+
await (releasePromise ??= (async () => {
|
|
47702
47990
|
try {
|
|
47703
|
-
await
|
|
47704
|
-
(resolve, reject) => ownedServer.close((error51) => error51 ? reject(error51) : resolve())
|
|
47705
|
-
);
|
|
47991
|
+
await stopAccepting();
|
|
47706
47992
|
} finally {
|
|
47707
|
-
|
|
47708
|
-
|
|
47993
|
+
const ownedIdentity = identity;
|
|
47994
|
+
const ownedOwnerLock = ownerLock;
|
|
47995
|
+
identity = null;
|
|
47996
|
+
ownerLock = null;
|
|
47997
|
+
try {
|
|
47998
|
+
unlinkIfOwned(socketPath, ownedIdentity);
|
|
47999
|
+
} finally {
|
|
48000
|
+
releaseSocketOwnerLock(ownedOwnerLock);
|
|
48001
|
+
}
|
|
48002
|
+
}
|
|
48003
|
+
})());
|
|
48004
|
+
};
|
|
48005
|
+
return {
|
|
48006
|
+
path: socketPath,
|
|
48007
|
+
get owned() {
|
|
48008
|
+
return ownerLock !== null;
|
|
48009
|
+
},
|
|
48010
|
+
stopAccepting,
|
|
48011
|
+
releaseOwnership,
|
|
48012
|
+
close: releaseOwnership
|
|
48013
|
+
};
|
|
48014
|
+
}
|
|
48015
|
+
async function startRuntimeAgentSocket(databaseFilePath) {
|
|
48016
|
+
let handler = null;
|
|
48017
|
+
let resolveHandler;
|
|
48018
|
+
let rejectHandler;
|
|
48019
|
+
const handlerPromise = new Promise((resolve, reject) => {
|
|
48020
|
+
resolveHandler = resolve;
|
|
48021
|
+
rejectHandler = reject;
|
|
48022
|
+
});
|
|
48023
|
+
void handlerPromise.catch(() => {
|
|
48024
|
+
});
|
|
48025
|
+
let accepting = true;
|
|
48026
|
+
const rejectUninitializedHandler = () => {
|
|
48027
|
+
if (handler) return;
|
|
48028
|
+
rejectHandler?.(new RvwError("PROCESS_FAILED", "rvw runtime\u304C\u521D\u671F\u5316\u3055\u308C\u308B\u524D\u306B\u505C\u6B62\u3057\u307E\u3057\u305F\u3002"));
|
|
48029
|
+
resolveHandler = void 0;
|
|
48030
|
+
rejectHandler = void 0;
|
|
48031
|
+
};
|
|
48032
|
+
const running = await startAgentSocketListener(
|
|
48033
|
+
databaseFilePath,
|
|
48034
|
+
async (rawRequest) => {
|
|
48035
|
+
const request = validateAgentRequest(rawRequest, databaseFilePath);
|
|
48036
|
+
if (request.operation === "ping") {
|
|
48037
|
+
const ping = external_exports.object({}).strict().safeParse(request.input);
|
|
48038
|
+
if (!ping.success) throw invalidSocketInput(ping.error);
|
|
48039
|
+
return pingResult(databaseFilePath);
|
|
48040
|
+
}
|
|
48041
|
+
if (request.operation === RUNTIME_VIEWER_OPEN_OPERATION) {
|
|
48042
|
+
const parsed = runtimeViewerOpenInputSchema.safeParse(request.input);
|
|
48043
|
+
if (!parsed.success) throw invalidSocketInput(parsed.error);
|
|
48044
|
+
return await (await handlerPromise).openViewer({
|
|
48045
|
+
...parsed.data.reference === void 0 ? {} : { reference: parsed.data.reference },
|
|
48046
|
+
cwd: parsed.data.cwd,
|
|
48047
|
+
requestedPort: parsed.data.requestedPort
|
|
48048
|
+
});
|
|
48049
|
+
}
|
|
48050
|
+
return await dispatchAgentSocketRequest((await handlerPromise).service, request);
|
|
48051
|
+
},
|
|
48052
|
+
{ retryOwnership: false }
|
|
48053
|
+
);
|
|
48054
|
+
return {
|
|
48055
|
+
path: running.path,
|
|
48056
|
+
get owned() {
|
|
48057
|
+
return running.owned;
|
|
48058
|
+
},
|
|
48059
|
+
setHandler(value) {
|
|
48060
|
+
if (!running.owned || !accepting) {
|
|
48061
|
+
throw new RvwError("PROCESS_FAILED", "\u6240\u6709\u3057\u3066\u3044\u306A\u3044runtime socket\u306F\u521D\u671F\u5316\u3067\u304D\u307E\u305B\u3093\u3002");
|
|
47709
48062
|
}
|
|
48063
|
+
if (handler) {
|
|
48064
|
+
throw new RvwError("INTERNAL_ERROR", "runtime socket\u306F\u521D\u671F\u5316\u6E08\u307F\u3067\u3059\u3002", {
|
|
48065
|
+
status: 500
|
|
48066
|
+
});
|
|
48067
|
+
}
|
|
48068
|
+
if (resolveDatabaseIdentity(value.service.database.filePath) !== resolveDatabaseIdentity(databaseFilePath)) {
|
|
48069
|
+
throw new RvwError("DATABASE_ERROR", "runtime\u3068Agent socket\u306Edatabase\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002", {
|
|
48070
|
+
details: {
|
|
48071
|
+
socketDatabasePath: resolveDatabaseIdentity(databaseFilePath),
|
|
48072
|
+
runtimeDatabasePath: resolveDatabaseIdentity(value.service.database.filePath)
|
|
48073
|
+
}
|
|
48074
|
+
});
|
|
48075
|
+
}
|
|
48076
|
+
handler = value;
|
|
48077
|
+
resolveHandler?.(value);
|
|
48078
|
+
resolveHandler = void 0;
|
|
48079
|
+
rejectHandler = void 0;
|
|
48080
|
+
},
|
|
48081
|
+
stopAccepting: async () => {
|
|
48082
|
+
accepting = false;
|
|
48083
|
+
rejectUninitializedHandler();
|
|
48084
|
+
await running.stopAccepting();
|
|
48085
|
+
},
|
|
48086
|
+
releaseOwnership: async () => {
|
|
48087
|
+
accepting = false;
|
|
48088
|
+
rejectUninitializedHandler();
|
|
48089
|
+
await running.releaseOwnership();
|
|
48090
|
+
},
|
|
48091
|
+
close: async () => {
|
|
48092
|
+
accepting = false;
|
|
48093
|
+
rejectUninitializedHandler();
|
|
48094
|
+
await running.releaseOwnership();
|
|
47710
48095
|
}
|
|
47711
48096
|
};
|
|
47712
48097
|
}
|
|
@@ -48067,6 +48452,9 @@ function formatCommentListOutput(result, state) {
|
|
|
48067
48452
|
var MAX_STDIN_BYTES = MAX_CLI_STDIN_BYTES;
|
|
48068
48453
|
var OPEN_WORKER_READY_TIMEOUT_MS = 12e4;
|
|
48069
48454
|
var OPEN_WORKER_PARENT_TIMEOUT_PADDING_MS = 5e3;
|
|
48455
|
+
var RUNTIME_REUSE_RETRY_MS = 50;
|
|
48456
|
+
var RUNTIME_VIEWER_HEARTBEAT_INTERVAL_MS = 3e4;
|
|
48457
|
+
var RUNTIME_VIEWER_REQUEST_TIMEOUT_MS = 5e3;
|
|
48070
48458
|
function writeJson(value) {
|
|
48071
48459
|
process.stdout.write(`${JSON.stringify(value)}
|
|
48072
48460
|
`);
|
|
@@ -48162,6 +48550,11 @@ function errorFromOpenWorker(error51) {
|
|
|
48162
48550
|
...error51.details === void 0 ? {} : { details: error51.details }
|
|
48163
48551
|
});
|
|
48164
48552
|
}
|
|
48553
|
+
function isRuntimeStoppingError(error51) {
|
|
48554
|
+
if (!(error51 instanceof RvwError) || error51.code !== "PROCESS_FAILED") return false;
|
|
48555
|
+
if (!error51.details || typeof error51.details !== "object") return false;
|
|
48556
|
+
return error51.details.reason === RUNTIME_STOPPING_REASON;
|
|
48557
|
+
}
|
|
48165
48558
|
async function completeBackgroundOpen(child, launchBrowser, options = {}) {
|
|
48166
48559
|
const readyTimeoutMs = options.readyTimeoutMs ?? OPEN_WORKER_READY_TIMEOUT_MS;
|
|
48167
48560
|
const viewerTimeoutMs = options.viewerTimeoutMs ?? DEFAULT_VIEWER_STARTUP_TIMEOUT_MS + OPEN_WORKER_PARENT_TIMEOUT_PADDING_MS;
|
|
@@ -48285,11 +48678,31 @@ function forkOpenWorker(reference, port) {
|
|
|
48285
48678
|
});
|
|
48286
48679
|
}
|
|
48287
48680
|
async function startBackgroundOpen(reference, port, dependencies = {}) {
|
|
48681
|
+
const input = {
|
|
48682
|
+
...reference === void 0 ? {} : { reference },
|
|
48683
|
+
cwd: process.cwd(),
|
|
48684
|
+
requestedPort: port
|
|
48685
|
+
};
|
|
48686
|
+
const launchBrowser = dependencies.launchBrowser ?? (async (url2) => await open_default(url2));
|
|
48687
|
+
let existing = null;
|
|
48688
|
+
try {
|
|
48689
|
+
existing = await (dependencies.tryRuntimeOpen ?? tryRuntimeViewerOpen)(input);
|
|
48690
|
+
} catch (error51) {
|
|
48691
|
+
if (!isRuntimeStoppingError(error51)) throw error51;
|
|
48692
|
+
}
|
|
48693
|
+
if (existing?.available) {
|
|
48694
|
+
await launchBrowser(existing.result.url);
|
|
48695
|
+
return existing.result.url;
|
|
48696
|
+
}
|
|
48697
|
+
if (existing?.reason === "database-mismatch") {
|
|
48698
|
+
throw new RvwError(
|
|
48699
|
+
"AGENT_SOCKET_UNAVAILABLE",
|
|
48700
|
+
"\u8D77\u52D5\u4E2D\u306Ervw runtime\u304C\u5225\u306Edatabase\u3092\u4F7F\u7528\u3057\u3066\u3044\u307E\u3059\u3002",
|
|
48701
|
+
{ details: existing.details }
|
|
48702
|
+
);
|
|
48703
|
+
}
|
|
48288
48704
|
const child = (dependencies.forkWorker ?? forkOpenWorker)(reference, port);
|
|
48289
|
-
return await completeBackgroundOpen(
|
|
48290
|
-
child,
|
|
48291
|
-
dependencies.launchBrowser ?? (async (url2) => await open_default(url2))
|
|
48292
|
-
);
|
|
48705
|
+
return await completeBackgroundOpen(child, launchBrowser);
|
|
48293
48706
|
}
|
|
48294
48707
|
async function sendOpenWorkerMessage(message) {
|
|
48295
48708
|
if (!process.send || !process.connected) return false;
|
|
@@ -48321,17 +48734,208 @@ async function waitForInitialViewer(firstViewerConnected, timeoutMs = DEFAULT_VI
|
|
|
48321
48734
|
void firstViewerConnected.then(() => finish("connected"));
|
|
48322
48735
|
});
|
|
48323
48736
|
}
|
|
48324
|
-
|
|
48737
|
+
function runtimeViewerOpenInput(reference, cwd, requestedPort) {
|
|
48738
|
+
return {
|
|
48739
|
+
...reference === void 0 ? {} : { reference },
|
|
48740
|
+
cwd,
|
|
48741
|
+
requestedPort
|
|
48742
|
+
};
|
|
48743
|
+
}
|
|
48744
|
+
function createRuntimeAgentSocketHandler(activeRuntime, running) {
|
|
48745
|
+
return {
|
|
48746
|
+
service: activeRuntime.service,
|
|
48747
|
+
openViewer: async (input) => {
|
|
48748
|
+
if (input.requestedPort !== 0 && input.requestedPort !== running.port) {
|
|
48749
|
+
throw new RvwError(
|
|
48750
|
+
"INVALID_INPUT",
|
|
48751
|
+
`\u540C\u3058database\u306Ervw runtime\u306Fport ${running.port} \u3067\u8D77\u52D5\u6E08\u307F\u3067\u3059\u3002`,
|
|
48752
|
+
{
|
|
48753
|
+
details: { activePort: running.port, requestedPort: input.requestedPort },
|
|
48754
|
+
suggestions: [
|
|
48755
|
+
"\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"
|
|
48756
|
+
]
|
|
48757
|
+
}
|
|
48758
|
+
);
|
|
48759
|
+
}
|
|
48760
|
+
const viewerLeaseId = running.reserveViewer();
|
|
48761
|
+
try {
|
|
48762
|
+
const opened = await activeRuntime.service.openPullRequest(input.reference, input.cwd);
|
|
48763
|
+
if (viewerLeaseId !== null) running.armViewerReservation(viewerLeaseId);
|
|
48764
|
+
const url2 = new URL(running.origin);
|
|
48765
|
+
url2.searchParams.set("pullRequestId", opened.pullRequest.id);
|
|
48766
|
+
if (viewerLeaseId !== null) url2.searchParams.set(VIEWER_OPEN_LEASE_QUERY, viewerLeaseId);
|
|
48767
|
+
return {
|
|
48768
|
+
url: url2.toString(),
|
|
48769
|
+
origin: running.origin,
|
|
48770
|
+
port: running.port,
|
|
48771
|
+
pullRequestId: opened.pullRequest.id,
|
|
48772
|
+
ownerPid: process.pid,
|
|
48773
|
+
...viewerLeaseId === null ? {} : { viewerLeaseId }
|
|
48774
|
+
};
|
|
48775
|
+
} catch (error51) {
|
|
48776
|
+
if (viewerLeaseId !== null) running.cancelViewerReservation(viewerLeaseId);
|
|
48777
|
+
throw error51;
|
|
48778
|
+
}
|
|
48779
|
+
}
|
|
48780
|
+
};
|
|
48781
|
+
}
|
|
48782
|
+
async function holdRuntimeViewerLease(result, dependencies = {}) {
|
|
48783
|
+
const viewerLeaseId = result.viewerLeaseId;
|
|
48784
|
+
if (viewerLeaseId === void 0) return;
|
|
48785
|
+
const fetchRequest = dependencies.fetch ?? fetch;
|
|
48786
|
+
const viewerId = randomUUID6();
|
|
48787
|
+
const requestTimeoutMs = dependencies.requestTimeoutMs ?? RUNTIME_VIEWER_REQUEST_TIMEOUT_MS;
|
|
48788
|
+
const heartbeatUrl = new URL("/api/meta/change-sequence", result.origin);
|
|
48789
|
+
const releaseUrl = new URL("/api/meta/viewers/release", result.origin);
|
|
48790
|
+
const heartbeat = async () => {
|
|
48791
|
+
const response = await fetchRequest(heartbeatUrl, {
|
|
48792
|
+
signal: AbortSignal.timeout(requestTimeoutMs),
|
|
48793
|
+
headers: {
|
|
48794
|
+
[VIEWER_ID_HEADER]: viewerId,
|
|
48795
|
+
[VIEWER_OPEN_LEASE_HEADER]: viewerLeaseId
|
|
48796
|
+
}
|
|
48797
|
+
});
|
|
48798
|
+
if (!response.ok) {
|
|
48799
|
+
throw new RvwError("PROCESS_FAILED", "rvw runtime\u306Eviewer lease\u3092\u66F4\u65B0\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002", {
|
|
48800
|
+
details: { status: response.status, origin: result.origin }
|
|
48801
|
+
});
|
|
48802
|
+
}
|
|
48803
|
+
};
|
|
48804
|
+
const stopped = Promise.withResolvers();
|
|
48805
|
+
let heartbeatError;
|
|
48806
|
+
let heartbeatInFlight = false;
|
|
48807
|
+
const onSignal = () => stopped.resolve("signal");
|
|
48808
|
+
process.once("SIGINT", onSignal);
|
|
48809
|
+
process.once("SIGTERM", onSignal);
|
|
48810
|
+
let interval;
|
|
48811
|
+
let registered = false;
|
|
48812
|
+
try {
|
|
48813
|
+
await heartbeat();
|
|
48814
|
+
registered = true;
|
|
48815
|
+
interval = setInterval(() => {
|
|
48816
|
+
if (heartbeatInFlight) return;
|
|
48817
|
+
heartbeatInFlight = true;
|
|
48818
|
+
void heartbeat().catch((error51) => {
|
|
48819
|
+
heartbeatError = error51;
|
|
48820
|
+
stopped.resolve("heartbeat-failed");
|
|
48821
|
+
}).finally(() => {
|
|
48822
|
+
heartbeatInFlight = false;
|
|
48823
|
+
});
|
|
48824
|
+
}, dependencies.heartbeatIntervalMs ?? RUNTIME_VIEWER_HEARTBEAT_INTERVAL_MS);
|
|
48825
|
+
interval.unref();
|
|
48826
|
+
const reason = await stopped.promise;
|
|
48827
|
+
if (reason === "heartbeat-failed") throw heartbeatError;
|
|
48828
|
+
} finally {
|
|
48829
|
+
if (interval) clearInterval(interval);
|
|
48830
|
+
process.removeListener("SIGINT", onSignal);
|
|
48831
|
+
process.removeListener("SIGTERM", onSignal);
|
|
48832
|
+
if (registered) {
|
|
48833
|
+
await fetchRequest(releaseUrl, {
|
|
48834
|
+
method: "POST",
|
|
48835
|
+
signal: AbortSignal.timeout(requestTimeoutMs),
|
|
48836
|
+
headers: {
|
|
48837
|
+
origin: result.origin,
|
|
48838
|
+
"content-type": "application/json"
|
|
48839
|
+
},
|
|
48840
|
+
body: JSON.stringify({ viewerId })
|
|
48841
|
+
}).catch(() => void 0);
|
|
48842
|
+
}
|
|
48843
|
+
}
|
|
48844
|
+
}
|
|
48845
|
+
async function closeOwnedRuntime(agentSocket, running, activeRuntime) {
|
|
48846
|
+
try {
|
|
48847
|
+
await agentSocket?.stopAccepting();
|
|
48848
|
+
} finally {
|
|
48849
|
+
try {
|
|
48850
|
+
await running?.close();
|
|
48851
|
+
} finally {
|
|
48852
|
+
try {
|
|
48853
|
+
activeRuntime?.close();
|
|
48854
|
+
} finally {
|
|
48855
|
+
await agentSocket?.releaseOwnership();
|
|
48856
|
+
}
|
|
48857
|
+
}
|
|
48858
|
+
}
|
|
48859
|
+
}
|
|
48860
|
+
async function acquireRuntimeOrReuseExisting(input, databaseFilePath, timeoutMs = OPEN_WORKER_READY_TIMEOUT_MS, dependencies = {}) {
|
|
48861
|
+
const startSocket = dependencies.startSocket ?? startRuntimeAgentSocket;
|
|
48862
|
+
const tryRuntimeOpen = dependencies.tryRuntimeOpen ?? tryRuntimeViewerOpen;
|
|
48863
|
+
const wait = dependencies.wait ?? (async (milliseconds) => {
|
|
48864
|
+
await new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
48865
|
+
});
|
|
48866
|
+
const now = dependencies.now ?? Date.now;
|
|
48867
|
+
const deadline = now() + timeoutMs;
|
|
48868
|
+
do {
|
|
48869
|
+
const candidate = await startSocket(databaseFilePath);
|
|
48870
|
+
if (candidate.owned) return { kind: "owned", agentSocket: candidate };
|
|
48871
|
+
await candidate.close();
|
|
48872
|
+
let response = null;
|
|
48873
|
+
try {
|
|
48874
|
+
response = await tryRuntimeOpen(input, databaseFilePath);
|
|
48875
|
+
} catch (error51) {
|
|
48876
|
+
if (!isRuntimeStoppingError(error51)) throw error51;
|
|
48877
|
+
}
|
|
48878
|
+
if (response?.available) return { kind: "reused", result: response.result };
|
|
48879
|
+
if (response?.reason === "database-mismatch") {
|
|
48880
|
+
throw new RvwError(
|
|
48881
|
+
"AGENT_SOCKET_UNAVAILABLE",
|
|
48882
|
+
"\u8D77\u52D5\u4E2D\u306Ervw runtime\u304C\u5225\u306Edatabase\u3092\u4F7F\u7528\u3057\u3066\u3044\u307E\u3059\u3002",
|
|
48883
|
+
{ details: response.details }
|
|
48884
|
+
);
|
|
48885
|
+
}
|
|
48886
|
+
await wait(RUNTIME_REUSE_RETRY_MS);
|
|
48887
|
+
} while (now() < deadline);
|
|
48888
|
+
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", {
|
|
48889
|
+
details: { timeoutMs }
|
|
48890
|
+
});
|
|
48891
|
+
}
|
|
48892
|
+
async function waitForWorkerParentDisconnect() {
|
|
48893
|
+
if (!process.connected) return;
|
|
48894
|
+
await new Promise((resolve) => process.once("disconnect", resolve));
|
|
48895
|
+
}
|
|
48896
|
+
async function runOpenServer(runtimeFactory, reference, port, openAutomatically, useAgentSocket, reuseExisting) {
|
|
48897
|
+
let activeRuntime;
|
|
48325
48898
|
let running;
|
|
48326
48899
|
let agentSocket;
|
|
48327
48900
|
try {
|
|
48901
|
+
if (useAgentSocket) {
|
|
48902
|
+
const databaseFilePath = databasePathConfiguration().filePath;
|
|
48903
|
+
if (reuseExisting) {
|
|
48904
|
+
const startup = await acquireRuntimeOrReuseExisting(
|
|
48905
|
+
runtimeViewerOpenInput(reference, process.cwd(), port),
|
|
48906
|
+
databaseFilePath
|
|
48907
|
+
);
|
|
48908
|
+
if (startup.kind === "reused") {
|
|
48909
|
+
const result = startup.result;
|
|
48910
|
+
process.stdout.write(`rvw: ${result.url}
|
|
48911
|
+
`);
|
|
48912
|
+
if (!openAutomatically) await holdRuntimeViewerLease(result);
|
|
48913
|
+
return;
|
|
48914
|
+
}
|
|
48915
|
+
agentSocket = startup.agentSocket;
|
|
48916
|
+
} else {
|
|
48917
|
+
agentSocket = await startRuntimeAgentSocket(databaseFilePath);
|
|
48918
|
+
if (!agentSocket.owned) {
|
|
48919
|
+
throw new RvwError(
|
|
48920
|
+
"PROCESS_FAILED",
|
|
48921
|
+
"\u540C\u3058database\u306Ervw runtime\u304C\u65E2\u306B\u8D77\u52D5\u4E2D\u306E\u305F\u3081foreground server\u3092\u958B\u59CB\u3067\u304D\u307E\u305B\u3093\u3002",
|
|
48922
|
+
{
|
|
48923
|
+
suggestions: [
|
|
48924
|
+
"\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"
|
|
48925
|
+
]
|
|
48926
|
+
}
|
|
48927
|
+
);
|
|
48928
|
+
}
|
|
48929
|
+
}
|
|
48930
|
+
}
|
|
48931
|
+
activeRuntime = runtimeFactory();
|
|
48328
48932
|
const opened = await activeRuntime.service.openPullRequest(reference, process.cwd());
|
|
48329
48933
|
running = await startServer(activeRuntime.service, {
|
|
48330
48934
|
port,
|
|
48331
48935
|
staticDirectory: staticDirectory(),
|
|
48332
48936
|
autoCloseWhenNoViewers: openAutomatically
|
|
48333
48937
|
});
|
|
48334
|
-
|
|
48938
|
+
agentSocket?.setHandler(createRuntimeAgentSocketHandler(activeRuntime, running));
|
|
48335
48939
|
const url2 = new URL(running.origin);
|
|
48336
48940
|
url2.searchParams.set("pullRequestId", opened.pullRequest.id);
|
|
48337
48941
|
process.stdout.write(`rvw: ${url2.toString()}
|
|
@@ -48342,31 +48946,38 @@ async function runOpenServer(activeRuntime, reference, port, openAutomatically,
|
|
|
48342
48946
|
process.stdout.write("rvw: viewer\u3092\u9589\u3058\u305F\u305F\u3081server\u3092\u505C\u6B62\u3057\u307E\u3059\u3002\n");
|
|
48343
48947
|
}
|
|
48344
48948
|
} finally {
|
|
48345
|
-
|
|
48346
|
-
await agentSocket?.close();
|
|
48347
|
-
} finally {
|
|
48348
|
-
try {
|
|
48349
|
-
await running?.close();
|
|
48350
|
-
} finally {
|
|
48351
|
-
activeRuntime.close();
|
|
48352
|
-
}
|
|
48353
|
-
}
|
|
48949
|
+
await closeOwnedRuntime(agentSocket, running, activeRuntime);
|
|
48354
48950
|
}
|
|
48355
48951
|
}
|
|
48356
|
-
async function runOpenWorker(
|
|
48952
|
+
async function runOpenWorker(runtimeFactory, reference, port) {
|
|
48953
|
+
let activeRuntime;
|
|
48357
48954
|
let running;
|
|
48358
48955
|
let agentSocket;
|
|
48359
48956
|
try {
|
|
48360
48957
|
if (!process.send || !process.connected) {
|
|
48361
48958
|
throw new RvwError("INVALID_INPUT", "\u5185\u90E8viewer worker\u306F\u89AACLI\u304B\u3089\u8D77\u52D5\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
48362
48959
|
}
|
|
48960
|
+
const databaseFilePath = databasePathConfiguration().filePath;
|
|
48961
|
+
const startup = await acquireRuntimeOrReuseExisting(
|
|
48962
|
+
runtimeViewerOpenInput(reference, process.cwd(), port),
|
|
48963
|
+
databaseFilePath
|
|
48964
|
+
);
|
|
48965
|
+
if (startup.kind === "reused") {
|
|
48966
|
+
const result = startup.result;
|
|
48967
|
+
if (!await sendOpenWorkerMessage({ type: "ready", url: result.url })) return;
|
|
48968
|
+
if (!await sendOpenWorkerMessage({ type: "viewer-connected" })) return;
|
|
48969
|
+
await waitForWorkerParentDisconnect();
|
|
48970
|
+
return;
|
|
48971
|
+
}
|
|
48972
|
+
agentSocket = startup.agentSocket;
|
|
48973
|
+
activeRuntime = runtimeFactory();
|
|
48363
48974
|
const opened = await activeRuntime.service.openPullRequest(reference, process.cwd());
|
|
48364
48975
|
running = await startServer(activeRuntime.service, {
|
|
48365
48976
|
port,
|
|
48366
48977
|
staticDirectory: staticDirectory(),
|
|
48367
48978
|
autoCloseWhenNoViewers: true
|
|
48368
48979
|
});
|
|
48369
|
-
agentSocket
|
|
48980
|
+
agentSocket.setHandler(createRuntimeAgentSocketHandler(activeRuntime, running));
|
|
48370
48981
|
const url2 = new URL(running.origin);
|
|
48371
48982
|
url2.searchParams.set("pullRequestId", opened.pullRequest.id);
|
|
48372
48983
|
if (!await sendOpenWorkerMessage({ type: "ready", url: url2.toString() })) return;
|
|
@@ -48386,15 +48997,7 @@ async function runOpenWorker(activeRuntime, reference, port) {
|
|
|
48386
48997
|
await sendOpenWorkerMessage({ type: "viewer-connected" });
|
|
48387
48998
|
await waitForServerShutdown(running.allViewersClosed);
|
|
48388
48999
|
} finally {
|
|
48389
|
-
|
|
48390
|
-
await agentSocket?.close();
|
|
48391
|
-
} finally {
|
|
48392
|
-
try {
|
|
48393
|
-
await running?.close();
|
|
48394
|
-
} finally {
|
|
48395
|
-
activeRuntime.close();
|
|
48396
|
-
}
|
|
48397
|
-
}
|
|
49000
|
+
await closeOwnedRuntime(agentSocket, running, activeRuntime);
|
|
48398
49001
|
}
|
|
48399
49002
|
}
|
|
48400
49003
|
var defaultRuntimeFactory = () => createRuntime();
|
|
@@ -48495,12 +49098,19 @@ function createProgram(runtimeFactory = defaultRuntimeFactory) {
|
|
|
48495
49098
|
`);
|
|
48496
49099
|
return;
|
|
48497
49100
|
}
|
|
48498
|
-
await runOpenServer(
|
|
49101
|
+
await runOpenServer(
|
|
49102
|
+
getRuntime,
|
|
49103
|
+
reference,
|
|
49104
|
+
options.port,
|
|
49105
|
+
options.open,
|
|
49106
|
+
useAgentSocket,
|
|
49107
|
+
!options.foreground
|
|
49108
|
+
);
|
|
48499
49109
|
}
|
|
48500
49110
|
);
|
|
48501
49111
|
program2.command("__open-worker", { hidden: true }).option("--reference <pull-request>").requiredOption("--port <port>", "listen port", parsePort).action(async (options) => {
|
|
48502
49112
|
try {
|
|
48503
|
-
await runOpenWorker(getRuntime
|
|
49113
|
+
await runOpenWorker(getRuntime, options.reference, options.port);
|
|
48504
49114
|
} catch (error51) {
|
|
48505
49115
|
const rvwError = asRvwError(error51);
|
|
48506
49116
|
const sent = await sendOpenWorkerMessage({
|
|
@@ -48861,8 +49471,12 @@ if (bundledCli || process.argv[1] && import.meta.url === pathToFileURL(process.a
|
|
|
48861
49471
|
await runCli();
|
|
48862
49472
|
}
|
|
48863
49473
|
export {
|
|
49474
|
+
acquireRuntimeOrReuseExisting,
|
|
49475
|
+
closeOwnedRuntime,
|
|
48864
49476
|
completeBackgroundOpen,
|
|
48865
49477
|
createProgram,
|
|
49478
|
+
createRuntimeAgentSocketHandler,
|
|
49479
|
+
holdRuntimeViewerLease,
|
|
48866
49480
|
runCli,
|
|
48867
49481
|
startBackgroundOpen,
|
|
48868
49482
|
waitForServerShutdown
|