stim 1.13.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/{activity-DfVKZTEB.mjs → activity-B2-kb7k0.mjs} +281 -41
- package/dist/{android-BHfAu2mf.mjs → android-CYmq0jNi.mjs} +2 -2
- package/dist/{android-CD8pr8Q2.mjs → android-Cu_L4RpL.mjs} +524 -412
- package/dist/{android-qx_31wJo.mjs → android-Db2eEMaf.mjs} +152 -65
- package/dist/android-cas-PnKfAdB2.mjs +167 -0
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/{app-install-CDFY2nUL.mjs → app-install-CAAplXAt.mjs} +162 -173
- package/dist/{budget-E5o91NR1.mjs → budget-CMiqghig.mjs} +1048 -77
- package/dist/{build-plan-BTa93o_r.mjs → build-plan-aeGMFX7e.mjs} +193 -650
- package/dist/build-progress-C2Jv1AtA.mjs +872 -0
- package/dist/build-slots-Df1ApSuH.mjs +127 -0
- package/dist/{cache-manifest-DWPF4RKJ.mjs → cache-manifest-DnUHBJaU.mjs} +2 -2
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{chrome-B5hWgQJS.mjs → chrome-BrcVWQyD.mjs} +4 -4
- package/dist/cli-0cX5s4NM.mjs +45 -0
- package/dist/cli.mjs +6 -42
- package/dist/client-C2IS36Qf.mjs +1333 -0
- package/dist/collector-run.mjs +8 -7
- package/dist/{command-output-BIL7rlX7.mjs → command-output-CliHHn7a.mjs} +1 -1
- package/dist/{config-0jCcMM0E.mjs → config-D0DbpZtM.mjs} +29 -29
- package/dist/{created-devices-Cd558h31.mjs → created-devices-BwVb3liH.mjs} +2 -2
- package/dist/{dependency-state-DNN0yfx6.mjs → dependency-state-BmsjKZ2H.mjs} +2 -2
- package/dist/{deps-2Wo81np9.mjs → deps-BFlKbOIp.mjs} +3 -3
- package/dist/{detached-entry-DJHoca49.mjs → detached-entry-CiTEgMR1.mjs} +1 -1
- package/dist/dev-client-CjzLoNs0.mjs +80 -0
- package/dist/{device-Cf7vl-so.mjs → device-BZ1IyS5A.mjs} +7 -7
- package/dist/device-capacity-DMuKC7nx.mjs +136 -0
- package/dist/device-host-worker.d.mts +1 -0
- package/dist/device-host-worker.mjs +769 -0
- package/dist/device-ios-DMQBUPus.mjs +381 -0
- package/dist/{device-lease-CL9dZf73.mjs → device-lease-W5Pi1q38.mjs} +43 -36
- package/dist/{device-pool-MuoiyRcu.mjs → device-pool-B2r38YjS.mjs} +4 -4
- package/dist/{device-remote-DT9ngZiD.mjs → device-remote-9ulPsdhY.mjs} +68 -162
- package/dist/{doctor-D2iysNNH.mjs → doctor-BcE5xsBn.mjs} +191 -99
- package/dist/{error-diagnostics-BoiOhck8.mjs → error-diagnostics-Cb0P1WLS.mjs} +12 -11
- package/dist/{exec-DK8KaVHK.mjs → exec-CaErVv7t.mjs} +5 -1
- package/dist/{gc-eA-PRBX8.mjs → gc-BuL1Genr.mjs} +430 -102
- package/dist/{android-cas-B9Kv9aIy.mjs → gradle-CmdOBq1d.mjs} +8 -294
- package/dist/{guide-BfZ0OmiP.mjs → guide-cCSGRFd3.mjs} +2052 -240
- package/dist/{guide-status-BaMYu55M.mjs → guide-status-CIoWK6mG.mjs} +3 -3
- package/dist/hosted-macos-DwowNU7W.mjs +447 -0
- package/dist/idle-shutdown-B5LPaNyY.mjs +122 -0
- package/dist/in-use-CndPMilN.mjs +110 -0
- package/dist/{ios-CmEzZiOj.mjs → ios-3CtCRhwr.mjs} +201 -10
- package/dist/{ios-CcfCeZ19.mjs → ios-Chob8ny7.mjs} +560 -259
- package/dist/{ios-device-BW-t_Lkv.mjs → ios-device-DERmMmk-.mjs} +12 -7
- package/dist/{ios-device-BiOsSVzd.mjs → ios-device-Ee7sDXfp.mjs} +1 -1
- package/dist/{launch-verify-CuJaBpEa.mjs → launch-verify-CLlofxRt.mjs} +42 -11
- package/dist/{logs-DcSRbC2t.mjs → logs-h9h6MUvE.mjs} +95 -13
- package/dist/machine-usage-D_YYMzfR.mjs +283 -0
- package/dist/machines-CYtOCqcj.mjs +259 -0
- package/dist/macos-BwtbUtTN.mjs +468 -0
- package/dist/macos-run.d.mts +5 -0
- package/dist/macos-run.mjs +2 -0
- package/dist/{merge-state-ytFQCeh4.mjs → merge-state-BnxLNQiM.mjs} +22 -12
- package/dist/{metro-BPeY1YMh.mjs → metro-Di8EN2Tb.mjs} +20 -120
- package/dist/{named-ports-n7tnJsI8.mjs → named-ports-Dj_XBNaL.mjs} +8 -64
- package/dist/native-run-DFDoIRbY.mjs +147 -0
- package/dist/{native-runtime-CiiFHt0e.mjs → native-runtime-i6OkVg-w.mjs} +11 -6
- package/dist/offload-worker.d.mts +121 -0
- package/dist/offload-worker.mjs +601 -0
- package/dist/{ownership-Bz2kETAS.mjs → ownership-BkYxUtuj.mjs} +3 -2
- package/dist/{page-BTu7I60K.mjs → page-QF_Ke10s.mjs} +7 -2
- package/dist/{ports-C5UutqpJ.mjs → ports-DddwttKM.mjs} +3 -3
- package/dist/prebuild-BvxDlD6C.mjs +213 -0
- package/dist/process-identity-BmRm1qV0.mjs +12 -0
- package/dist/{project-DGeclhvO.mjs → project-CV3tDFHl.mjs} +9 -18
- package/dist/pull-request-pxnDCQzn.mjs +322 -0
- package/dist/pull-requests.d.mts +120 -0
- package/dist/pull-requests.mjs +2 -0
- package/dist/recordings-GEXp4iBT.mjs +37 -0
- package/dist/{reload-C-cV5yy_.mjs → reload-ChPiwvot.mjs} +70 -22
- package/dist/{remote-cache--aehr4Pr.mjs → remote-cache-CO2elm_b.mjs} +4 -4
- package/dist/run-B-xqRrsg.mjs +119 -0
- package/dist/{server-bare-Bq8BpSIo.mjs → server-bare-X7PUgizL.mjs} +60 -13
- package/dist/{server-expo-DUCg52-K.mjs → server-expo-DhtX6bom.mjs} +6 -10
- package/dist/server-expo-KJeD109I.mjs +2 -0
- package/dist/{settings-xB0Frkg6.mjs → settings-CduVcoxj.mjs} +77 -26
- package/dist/{settings-ssVBToDR.mjs → settings-DbL6uhH8.mjs} +16 -10
- package/dist/settings.schema.json +357 -2
- package/dist/{simslim-Bbg9UWrt.mjs → simslim-Ciluxlq4.mjs} +8 -132
- package/dist/slot-launch-BY0BrOLh.mjs +65 -0
- package/dist/{spawn-claims-PT8aQpCa.mjs → spawn-claims-D0XfSe8u.mjs} +1 -1
- package/dist/spawn-entry-DncpJvWL.mjs +16 -0
- package/dist/stage-CzaiwFsI.mjs +143 -0
- package/dist/start-CPO4wRg7.mjs +2 -0
- package/dist/{start-BZhItkiL.mjs → start-CUD9nasA.mjs} +108 -61
- package/dist/state-B4PQFXMW.d.mts +12 -0
- package/dist/state-BxCgeTQu.mjs +41 -0
- package/dist/{state-DwAU2_-D.mjs → state-CaeaHbDA.mjs} +7 -4
- package/dist/{state-l1pYwOre.mjs → state-DFm77wRn.mjs} +67 -5
- package/dist/stats-DBLLFmKd.mjs +66 -0
- package/dist/{status-TJlL0HWo.mjs → status-DYXxNOT0.mjs} +425 -260
- package/dist/{status-sszP4XKU.mjs → status-l84Gbvp2.mjs} +122 -20
- package/dist/stdout-reader-C8yjre1x.mjs +23 -0
- package/dist/stim-desktop-Cnz8CPnl.mjs +63 -0
- package/dist/stim-footprint.swift +32 -0
- package/dist/{stim-installations-CINXy_su.mjs → stim-installations-QMEI32v1.mjs} +1 -1
- package/dist/{stop-BZ2qMiBP.mjs → stop-Bad61z_2.mjs} +128 -19
- package/dist/stop-Bvf1MflS.mjs +48 -0
- package/dist/{stop-DskDKNTU.mjs → stop-CceYh1yG.mjs} +2 -2
- package/dist/stop-cause-CZ_Mr-v9.mjs +665 -0
- package/dist/supervisor-run.d.mts +44 -12
- package/dist/supervisor-run.mjs +276 -33
- package/dist/support-CDQbDkL5.mjs +315 -0
- package/dist/support-WLOzVKUv.mjs +176 -0
- package/dist/teardown-BYuQafiA.mjs +718 -0
- package/dist/{xcode-LM6A8cNZ.mjs → toolchain-DmeYjXD9.mjs} +363 -13
- package/dist/warm-progress-DVHLN4uC.mjs +463 -0
- package/dist/{idle-DxLi5OkN.mjs → watchman-Bx0wceoF.mjs} +55 -8
- package/dist/{web-sWXd5iek.mjs → web-k6w8-HnE.mjs} +39 -22
- package/dist/web-run.mjs +326 -13
- package/dist/workspace-process-lock-BL7Q0HCO.mjs +57 -0
- package/dist/workspace-state-CL2V2Ons.mjs +371 -0
- package/dist/worktree-BT_uULFx.mjs +2 -0
- package/dist/{worktree-DeBQSVtR.mjs → worktree-C0c5Udwa.mjs} +55 -54
- package/dist/{worktree-D4Do_XiQ.mjs → worktree-qXKzADSC.mjs} +161 -255
- package/package.json +10 -5
- package/shim/bundle-response.cjs +55 -10
- package/shim/bundle-response.d.cts +1 -0
- package/shim/expo-metro-config.cjs +10 -2
- package/dist/build-progress-l7d-X-ZP.mjs +0 -247
- package/dist/in-use-wYEaKQM9.mjs +0 -249
- package/dist/ownership-PUP4Dwai.mjs +0 -1138
- package/dist/server-expo-BeYwP_Xy.mjs +0 -2
- package/dist/slot-launch-BIWEW-wI.mjs +0 -19
- package/dist/start-Rw2GD3nV.mjs +0 -2
- package/dist/stats-CaSwmsSZ.mjs +0 -62
- package/dist/stats-D8rUTPHd.mjs +0 -368
- package/dist/stim-desktop-CXt8-Z3J.mjs +0 -40
- package/dist/worktree-3cBa-bQt.mjs +0 -2
- package/dist/{metro-store-DzeWkfqW.mjs → metro-store-CDDZHtPl.mjs} +1 -1
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { t as getExecutor } from "./exec-CaErVv7t.mjs";
|
|
2
|
+
import { a as updateWorkspaceState, r as readWorkspaceState } from "./workspace-state-CL2V2Ons.mjs";
|
|
3
|
+
import { r as detectIsExpo } from "./project-CV3tDFHl.mjs";
|
|
4
|
+
import { a as spawnDeclared } from "./spawn-claims-D0XfSe8u.mjs";
|
|
5
|
+
import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
|
|
6
|
+
import { i as expoBinRefusal, r as expoBinPath } from "./server-expo-DhtX6bom.mjs";
|
|
7
|
+
import { existsSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
//#region src/engine/prebuild.ts
|
|
10
|
+
const PREBUILD_ERROR = "STIM_PREBUILD_FAILED";
|
|
11
|
+
const LAST_LINES = 20;
|
|
12
|
+
function nativeDirName(platform) {
|
|
13
|
+
return platform === "android" ? "android" : "ios";
|
|
14
|
+
}
|
|
15
|
+
function nativeDir(root, platform) {
|
|
16
|
+
return join(root, nativeDirName(platform));
|
|
17
|
+
}
|
|
18
|
+
function nativeDirInFingerprint(sources, platform) {
|
|
19
|
+
const dir = nativeDirName(platform);
|
|
20
|
+
return sources.some((source) => source.type === "dir" && source.filePath === dir && source.hash != null);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* @expo/fingerprint leaves a native directory out of the hash when git ignores it (CNG), so the cache
|
|
24
|
+
* key only covers that directory when this workspace's recorded prebuild ran on the same fingerprint.
|
|
25
|
+
*/
|
|
26
|
+
function prebuildAction({ isExpo, nativeDirExists, nativeDirFingerprinted, nativeDirTracked, generatedFrom, fingerprint }) {
|
|
27
|
+
if (!isExpo) return "none";
|
|
28
|
+
if (!nativeDirExists) return "generate";
|
|
29
|
+
if (nativeDirFingerprinted || generatedFrom === fingerprint) return "none";
|
|
30
|
+
return nativeDirTracked ? "refuse" : "regenerate";
|
|
31
|
+
}
|
|
32
|
+
function prebuildRecord(state) {
|
|
33
|
+
const record = state?.prebuild;
|
|
34
|
+
return record && typeof record === "object" ? record : {};
|
|
35
|
+
}
|
|
36
|
+
function gitTracksNativeDir(root, platform) {
|
|
37
|
+
try {
|
|
38
|
+
return getExecutor().runFile("git", [
|
|
39
|
+
"-C",
|
|
40
|
+
root,
|
|
41
|
+
"ls-files",
|
|
42
|
+
"--",
|
|
43
|
+
nativeDirName(platform)
|
|
44
|
+
], { env: {
|
|
45
|
+
LC_ALL: "C",
|
|
46
|
+
LANGUAGE: "C"
|
|
47
|
+
} }).trim() !== "";
|
|
48
|
+
} catch (error) {
|
|
49
|
+
if (error?.code === "ENOENT") return false;
|
|
50
|
+
return !/not a git repository \(or any (of the parent directories|parent up to mount point)/.test(String(error?.message));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function planPrebuild(root, platform, { isExpo, fingerprint, sources }) {
|
|
54
|
+
const nativeDirExists = existsSync(nativeDir(root, platform));
|
|
55
|
+
const fingerprinted = nativeDirInFingerprint(sources, platform);
|
|
56
|
+
const generatedFrom = prebuildRecord(readWorkspaceState(root))[platform];
|
|
57
|
+
return prebuildAction({
|
|
58
|
+
isExpo,
|
|
59
|
+
nativeDirExists,
|
|
60
|
+
nativeDirFingerprinted: fingerprinted,
|
|
61
|
+
nativeDirTracked: nativeDirExists && !fingerprinted && gitTracksNativeDir(root, platform),
|
|
62
|
+
generatedFrom: typeof generatedFrom === "string" ? generatedFrom : null,
|
|
63
|
+
fingerprint
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function recordPrebuild(root, platform, fingerprint) {
|
|
67
|
+
updateWorkspaceState(root, (state) => ({
|
|
68
|
+
...state,
|
|
69
|
+
prebuild: {
|
|
70
|
+
...prebuildRecord(state),
|
|
71
|
+
[platform]: fingerprint
|
|
72
|
+
}
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
function staleNativeDirRefusal(platform) {
|
|
76
|
+
const dir = nativeDirName(platform);
|
|
77
|
+
return {
|
|
78
|
+
code: PREBUILD_ERROR,
|
|
79
|
+
message: `The fingerprint leaves ${dir}/ out of the cache key, and Stim cannot show that ${dir}/ was generated from the current app config. Git tracks files in it, or could not say whether it does, so Stim will not regenerate it with \`expo prebuild --clean\`.`,
|
|
80
|
+
remedy: `Stop excluding ${dir}/ from the fingerprint (check .fingerprintignore) so the cache key covers its files, or add ${dir}/ to .gitignore and untrack it so Stim regenerates it from the app config.`
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function prebuildRefusal({ isExpo, platform, nativeDirExists }) {
|
|
84
|
+
if (nativeDirExists || isExpo) return null;
|
|
85
|
+
const dir = nativeDirName(platform);
|
|
86
|
+
return {
|
|
87
|
+
code: PREBUILD_ERROR,
|
|
88
|
+
message: `This project has no ${dir}/ directory and is not an Expo (CNG) project, so Stim cannot generate one.`,
|
|
89
|
+
remedy: `Check out or generate the native project (\`npx @react-native-community/cli init\` produced one originally), or add \`expo\` to the project so \`expo prebuild\` can create ${dir}/.`
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function prebuildFailure(logWriter, result) {
|
|
93
|
+
logWriter?.write?.({
|
|
94
|
+
src: "build",
|
|
95
|
+
level: "error",
|
|
96
|
+
msg: result.reason || "Expo prebuild failed.",
|
|
97
|
+
event: "prebuild_failed"
|
|
98
|
+
});
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
async function runPrebuild(root, platform, logWriter, { spawnFn = null, now = Date.now, isExpo = null, clean = false } = {}) {
|
|
102
|
+
const dirExists = existsSync(nativeDir(root, platform));
|
|
103
|
+
const refusal = prebuildRefusal({
|
|
104
|
+
isExpo: isExpo === null ? detectIsExpo(root) : isExpo,
|
|
105
|
+
platform,
|
|
106
|
+
nativeDirExists: dirExists
|
|
107
|
+
});
|
|
108
|
+
if (refusal) return prebuildFailure(logWriter, {
|
|
109
|
+
failed: true,
|
|
110
|
+
code: refusal.code,
|
|
111
|
+
reason: refusal.message,
|
|
112
|
+
remedy: refusal.remedy,
|
|
113
|
+
error: refusal,
|
|
114
|
+
lastLines: []
|
|
115
|
+
});
|
|
116
|
+
const bin = expoBinPath(root);
|
|
117
|
+
if (!bin) {
|
|
118
|
+
const binRefusal = expoBinRefusal(root, "prebuild");
|
|
119
|
+
return prebuildFailure(logWriter, {
|
|
120
|
+
failed: true,
|
|
121
|
+
code: PREBUILD_ERROR,
|
|
122
|
+
reason: binRefusal.message,
|
|
123
|
+
remedy: binRefusal.remedy,
|
|
124
|
+
lastLines: []
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
const spawn = spawnFn || ((cmd, args, opts) => getExecutor().spawn(cmd, args, opts));
|
|
128
|
+
const startedAt = now();
|
|
129
|
+
const tail = [];
|
|
130
|
+
const push = (line) => {
|
|
131
|
+
const msg = stripAnsi(String(line)).trimEnd();
|
|
132
|
+
if (!msg.trim()) return;
|
|
133
|
+
tail.push(msg);
|
|
134
|
+
if (tail.length > LAST_LINES) tail.shift();
|
|
135
|
+
logWriter?.write?.({
|
|
136
|
+
src: "build",
|
|
137
|
+
level: "debug",
|
|
138
|
+
msg,
|
|
139
|
+
raw: true,
|
|
140
|
+
event: "prebuild"
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
let child;
|
|
144
|
+
try {
|
|
145
|
+
child = spawnDeclared(() => spawn(bin, [
|
|
146
|
+
"prebuild",
|
|
147
|
+
"-p",
|
|
148
|
+
platform,
|
|
149
|
+
"--no-install",
|
|
150
|
+
...clean ? ["--clean"] : []
|
|
151
|
+
], {
|
|
152
|
+
cwd: root,
|
|
153
|
+
stdio: [
|
|
154
|
+
"ignore",
|
|
155
|
+
"pipe",
|
|
156
|
+
"pipe"
|
|
157
|
+
],
|
|
158
|
+
env: {
|
|
159
|
+
...process.env,
|
|
160
|
+
FORCE_COLOR: "0",
|
|
161
|
+
CI: "1"
|
|
162
|
+
}
|
|
163
|
+
}));
|
|
164
|
+
} catch (err) {
|
|
165
|
+
return prebuildFailure(logWriter, {
|
|
166
|
+
failed: true,
|
|
167
|
+
code: PREBUILD_ERROR,
|
|
168
|
+
reason: `Could not run \`expo prebuild\`: ${err?.message || err}`,
|
|
169
|
+
lastLines: []
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
const outReader = createLineReader(push);
|
|
173
|
+
const errReader = createLineReader(push);
|
|
174
|
+
child.stdout?.setEncoding?.("utf-8");
|
|
175
|
+
child.stderr?.setEncoding?.("utf-8");
|
|
176
|
+
child.stdout?.on("data", (chunk) => outReader.push(chunk));
|
|
177
|
+
child.stderr?.on("data", (chunk) => errReader.push(chunk));
|
|
178
|
+
const result = await waitForChild(child);
|
|
179
|
+
outReader.flush();
|
|
180
|
+
errReader.flush();
|
|
181
|
+
const durationMs = now() - startedAt;
|
|
182
|
+
if (result.error) return prebuildFailure(logWriter, {
|
|
183
|
+
failed: true,
|
|
184
|
+
code: PREBUILD_ERROR,
|
|
185
|
+
reason: `Could not run \`expo prebuild\`: ${result.error?.message || result.error}`,
|
|
186
|
+
lastLines: tail.slice(),
|
|
187
|
+
durationMs
|
|
188
|
+
});
|
|
189
|
+
if (result.code !== 0) {
|
|
190
|
+
const how = result.signal ? `signal ${result.signal}` : `exit code ${result.code}`;
|
|
191
|
+
return prebuildFailure(logWriter, {
|
|
192
|
+
failed: true,
|
|
193
|
+
code: PREBUILD_ERROR,
|
|
194
|
+
reason: `\`expo prebuild -p ${platform}\` failed (${how}).`,
|
|
195
|
+
lastLines: tail.slice(),
|
|
196
|
+
durationMs
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
if (!existsSync(nativeDir(root, platform))) return prebuildFailure(logWriter, {
|
|
200
|
+
failed: true,
|
|
201
|
+
code: PREBUILD_ERROR,
|
|
202
|
+
reason: `\`expo prebuild -p ${platform}\` succeeded but did not create ${nativeDirName(platform)}/.`,
|
|
203
|
+
lastLines: tail.slice(),
|
|
204
|
+
durationMs
|
|
205
|
+
});
|
|
206
|
+
return {
|
|
207
|
+
ok: true,
|
|
208
|
+
durationMs,
|
|
209
|
+
nativeDir: nativeDir(root, platform)
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
//#endregion
|
|
213
|
+
export { staleNativeDirRefusal as i, recordPrebuild as n, runPrebuild as r, planPrebuild as t };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { n as __exportAll, r as __reExport } from "./rolldown-runtime-BsOwBuO_.mjs";
|
|
2
|
+
//#region src/ownership-claim.ts
|
|
3
|
+
var ownership_claim_exports = /* @__PURE__ */ __exportAll({});
|
|
4
|
+
import * as import__stim_cli_core_ownership_claim from "@stim-cli/core/ownership-claim";
|
|
5
|
+
__reExport(ownership_claim_exports, import__stim_cli_core_ownership_claim);
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/process-identity.ts
|
|
8
|
+
var process_identity_exports = /* @__PURE__ */ __exportAll({});
|
|
9
|
+
import * as import__stim_cli_core_process_identity from "@stim-cli/core/process-identity";
|
|
10
|
+
__reExport(process_identity_exports, import__stim_cli_core_process_identity);
|
|
11
|
+
//#endregion
|
|
12
|
+
export { ownership_claim_exports as n, process_identity_exports as t };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { _ as loadConfig, g as isPathPrefix, l as findEnclosingWorktreeRoot, p as getProject } from "./config-
|
|
2
|
-
import { y as repoRoot } from "./worktree-
|
|
1
|
+
import { _ as loadConfig$1, g as isPathPrefix, l as findEnclosingWorktreeRoot, p as getProject } from "./config-D0DbpZtM.mjs";
|
|
2
|
+
import { y as repoRoot } from "./worktree-C0c5Udwa.mjs";
|
|
3
3
|
import { existsSync, readFileSync, realpathSync } from "fs";
|
|
4
4
|
import { basename, dirname, join, resolve } from "path";
|
|
5
|
+
import { findProjectRoot, findProjectRoot as findProjectRoot$1 } from "@stim-cli/core/state";
|
|
5
6
|
//#region src/workspace/project.ts
|
|
6
7
|
/**
|
|
7
8
|
* The realpath of `name`'s package.json in the nearest `node_modules` at or above `projectRoot`.
|
|
@@ -37,23 +38,13 @@ const NO_PROJECT_REFUSAL = {
|
|
|
37
38
|
message: "Not in a React Native project (no package.json found).",
|
|
38
39
|
remedy: "Run this from the app directory -- the one holding package.json."
|
|
39
40
|
};
|
|
40
|
-
function findProjectRoot(startDir) {
|
|
41
|
-
let dir;
|
|
42
|
-
try {
|
|
43
|
-
dir = realpathSync(resolve(startDir));
|
|
44
|
-
} catch {
|
|
45
|
-
dir = resolve(startDir);
|
|
46
|
-
}
|
|
47
|
-
while (true) {
|
|
48
|
-
if (existsSync(join(dir, "package.json"))) return dir;
|
|
49
|
-
const parent = dirname(dir);
|
|
50
|
-
if (parent === dir) return null;
|
|
51
|
-
dir = parent;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
41
|
function findServerWorkspace(startDir) {
|
|
55
42
|
const nearest = findProjectRoot(startDir);
|
|
56
43
|
if (!nearest) return null;
|
|
44
|
+
if (existsSync(join(nearest, "Package.swift"))) return {
|
|
45
|
+
root: nearest,
|
|
46
|
+
from: null
|
|
47
|
+
};
|
|
57
48
|
if (appProjectProblem(nearest)?.kind !== "not-an-app") return {
|
|
58
49
|
root: nearest,
|
|
59
50
|
from: null
|
|
@@ -68,7 +59,7 @@ function findServerWorkspace(startDir) {
|
|
|
68
59
|
from: null
|
|
69
60
|
};
|
|
70
61
|
const worktree = expandedRealpath(top);
|
|
71
|
-
const apps = Object.keys(loadConfig()?.projects ?? {}).filter((path) => {
|
|
62
|
+
const apps = Object.keys(loadConfig$1()?.projects ?? {}).filter((path) => {
|
|
72
63
|
if (path === nearest || !isPathPrefix(worktree, expandedRealpath(path)) || appProjectProblem(path) !== null) return false;
|
|
73
64
|
const owner = repoRoot(path);
|
|
74
65
|
return owner !== null && expandedRealpath(owner) === worktree;
|
|
@@ -213,4 +204,4 @@ function readAppConfigText(projectRoot) {
|
|
|
213
204
|
return null;
|
|
214
205
|
}
|
|
215
206
|
//#endregion
|
|
216
|
-
export { findProjectRoot as a, ownedDeviceLabel as c, readAppJson as d, resolvePackageJson as f, findCommandWorkspace as i, projectShortcut as l, appProjectProblem as n, findServerWorkspace as o, detectIsExpo as r, isPackageResolvable as s, NO_PROJECT_REFUSAL as t, readAppConfigText as u };
|
|
207
|
+
export { findProjectRoot$1 as a, ownedDeviceLabel as c, readAppJson as d, resolvePackageJson as f, findCommandWorkspace as i, projectShortcut as l, appProjectProblem as n, findServerWorkspace as o, detectIsExpo as r, isPackageResolvable as s, NO_PROJECT_REFUSAL as t, readAppConfigText as u };
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { t as getExecutor } from "./exec-CaErVv7t.mjs";
|
|
2
|
+
//#region src/workspace/pull-request.ts
|
|
3
|
+
const GH_TIMEOUT_MS = 2e4;
|
|
4
|
+
const GH_ENV = {
|
|
5
|
+
GH_PROMPT_DISABLED: "1",
|
|
6
|
+
GH_NO_UPDATE_NOTIFIER: "1",
|
|
7
|
+
NO_COLOR: "1"
|
|
8
|
+
};
|
|
9
|
+
const GH_SCALAR_FIELDS = "number,state,url,headRefOid,mergedAt,closedAt,isCrossRepository,isDraft";
|
|
10
|
+
const GH_FIELDS = `${GH_SCALAR_FIELDS},headRepository,headRepositoryOwner`;
|
|
11
|
+
const GH_GRAPHQL_REPO_SELECTION = "headRepository { name } headRepositoryOwner { login }";
|
|
12
|
+
const GH_DETAIL_FIELDS = "title reviewDecision commits(last: 1) { nodes { commit { statusCheckRollup { contexts(first: 0) { checkRunCountsByState { state count } statusContextCountsByState { state count } } } } } }";
|
|
13
|
+
const SIGNED_OUT_EXIT = 4;
|
|
14
|
+
const PASSING = /* @__PURE__ */ new Set([
|
|
15
|
+
"SUCCESS",
|
|
16
|
+
"NEUTRAL",
|
|
17
|
+
"SKIPPED",
|
|
18
|
+
"COMPLETED"
|
|
19
|
+
]);
|
|
20
|
+
const FAILING = /* @__PURE__ */ new Set([
|
|
21
|
+
"FAILURE",
|
|
22
|
+
"ERROR",
|
|
23
|
+
"TIMED_OUT",
|
|
24
|
+
"CANCELLED",
|
|
25
|
+
"ACTION_REQUIRED",
|
|
26
|
+
"STARTUP_FAILURE",
|
|
27
|
+
"STALE"
|
|
28
|
+
]);
|
|
29
|
+
const PENDING = /* @__PURE__ */ new Set([
|
|
30
|
+
"QUEUED",
|
|
31
|
+
"IN_PROGRESS",
|
|
32
|
+
"WAITING",
|
|
33
|
+
"PENDING",
|
|
34
|
+
"REQUESTED",
|
|
35
|
+
"EXPECTED"
|
|
36
|
+
]);
|
|
37
|
+
/** Sums a head commit's check runs and commit statuses by outcome; null when the commit has no checks. */
|
|
38
|
+
function checkCounts(rollup) {
|
|
39
|
+
if (!rollup) return null;
|
|
40
|
+
const counts = {
|
|
41
|
+
passing: 0,
|
|
42
|
+
failing: 0,
|
|
43
|
+
pending: 0
|
|
44
|
+
};
|
|
45
|
+
const contexts = rollup.contexts;
|
|
46
|
+
for (const { state, count } of [...contexts?.checkRunCountsByState ?? [], ...contexts?.statusContextCountsByState ?? []]) {
|
|
47
|
+
if (!Number.isInteger(count) || count <= 0) continue;
|
|
48
|
+
if (PASSING.has(state)) counts.passing += count;
|
|
49
|
+
else if (FAILING.has(state)) counts.failing += count;
|
|
50
|
+
else if (PENDING.has(state)) counts.pending += count;
|
|
51
|
+
}
|
|
52
|
+
return counts;
|
|
53
|
+
}
|
|
54
|
+
function reviewDecisionOf(value) {
|
|
55
|
+
if (value === "APPROVED") return "approved";
|
|
56
|
+
if (value === "CHANGES_REQUESTED") return "changes-requested";
|
|
57
|
+
if (value === "REVIEW_REQUIRED") return "review-required";
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
function detailOf(pull) {
|
|
61
|
+
if (typeof pull.title !== "string") return {};
|
|
62
|
+
return {
|
|
63
|
+
title: pull.title,
|
|
64
|
+
reviewDecision: reviewDecisionOf(pull.reviewDecision),
|
|
65
|
+
checks: checkCounts(pull.commits?.nodes?.[0]?.commit?.statusCheckRollup)
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function stateOf(state) {
|
|
69
|
+
if (state === "OPEN") return "open";
|
|
70
|
+
if (state === "MERGED") return "merged";
|
|
71
|
+
if (state === "CLOSED") return "closed";
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
function epoch(text) {
|
|
75
|
+
const at = text ? Date.parse(text) : NaN;
|
|
76
|
+
return Number.isFinite(at) ? at : null;
|
|
77
|
+
}
|
|
78
|
+
function headRepoOf(pull) {
|
|
79
|
+
const owner = pull.headRepositoryOwner?.login;
|
|
80
|
+
const name = pull.headRepository?.name;
|
|
81
|
+
return owner && name ? `${owner.toLowerCase()}/${name.toLowerCase()}` : null;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Picks the pull request that describes `head` among those `gh pr list --head <branch>` returned. One whose head is
|
|
85
|
+
* `head` wins, then one whose head contains `head`, then one whose head `head` contains. An open one wins a tier,
|
|
86
|
+
* then the newest. A pull request unrelated to `head` is from an earlier use of the branch name and is ignored. A
|
|
87
|
+
* cross-repository pull request is kept only when its head repository is one of `ownRepos` (this checkout's own git
|
|
88
|
+
* remotes, lowercased "owner/name"); otherwise it only shares the branch name with a stranger's fork and is ignored.
|
|
89
|
+
* `isAncestor(a, b)` answers whether commit `a` is an ancestor of commit `b`, and false when git cannot tell.
|
|
90
|
+
*/
|
|
91
|
+
function selectPullRequest(pulls, head, isAncestor, ownRepos = /* @__PURE__ */ new Set()) {
|
|
92
|
+
const known = pulls.flatMap((pull) => {
|
|
93
|
+
if (!pull || typeof pull !== "object") return [];
|
|
94
|
+
const state = stateOf(pull.state);
|
|
95
|
+
if (!state || !pull.headRefOid) return [];
|
|
96
|
+
if (pull.isCrossRepository) {
|
|
97
|
+
const repo = headRepoOf(pull);
|
|
98
|
+
if (!repo || !ownRepos.has(repo)) return [];
|
|
99
|
+
}
|
|
100
|
+
return [{
|
|
101
|
+
pull,
|
|
102
|
+
state
|
|
103
|
+
}];
|
|
104
|
+
});
|
|
105
|
+
const tiers = [
|
|
106
|
+
known.filter(({ pull }) => pull.headRefOid === head),
|
|
107
|
+
known.filter(({ pull }) => pull.headRefOid !== head && isAncestor(head, pull.headRefOid)),
|
|
108
|
+
known.filter(({ pull }) => pull.headRefOid !== head && isAncestor(pull.headRefOid, head))
|
|
109
|
+
];
|
|
110
|
+
const tier = tiers.findIndex((entries) => entries.length > 0);
|
|
111
|
+
if (tier < 0) return null;
|
|
112
|
+
const { pull, state } = tiers[tier].toSorted((a, b) => Number(b.state === "open") - Number(a.state === "open") || b.pull.number - a.pull.number)[0];
|
|
113
|
+
return {
|
|
114
|
+
number: pull.number,
|
|
115
|
+
state,
|
|
116
|
+
draft: pull.isDraft === true,
|
|
117
|
+
url: pull.url,
|
|
118
|
+
head: pull.headRefOid,
|
|
119
|
+
containsHead: tier < 2,
|
|
120
|
+
endedAt: state === "merged" ? epoch(pull.mergedAt) : state === "closed" ? epoch(pull.closedAt) : null,
|
|
121
|
+
...detailOf(pull)
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function firstLine(error) {
|
|
125
|
+
const { stderr, message } = error;
|
|
126
|
+
const text = String(stderr ?? "").trim() || String(message ?? error);
|
|
127
|
+
return text.split("\n")[0] ?? text;
|
|
128
|
+
}
|
|
129
|
+
function ghFailure(error, command) {
|
|
130
|
+
if (error.status === SIGNED_OUT_EXIT) return {
|
|
131
|
+
unavailable: "gh is not signed in; run `gh auth login`",
|
|
132
|
+
sticky: true
|
|
133
|
+
};
|
|
134
|
+
if (error.code === "ETIMEDOUT") return {
|
|
135
|
+
unavailable: `${command} did not answer within ${GH_TIMEOUT_MS / 1e3}s`,
|
|
136
|
+
sticky: true
|
|
137
|
+
};
|
|
138
|
+
return {
|
|
139
|
+
unavailable: `${command} failed: ${firstLine(error)}`,
|
|
140
|
+
sticky: false
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function ancestry(cwd) {
|
|
144
|
+
const exec = getExecutor();
|
|
145
|
+
return (ancestor, descendant) => exec.runFileQuiet("git", [
|
|
146
|
+
"-C",
|
|
147
|
+
cwd,
|
|
148
|
+
"merge-base",
|
|
149
|
+
"--is-ancestor",
|
|
150
|
+
ancestor,
|
|
151
|
+
descendant
|
|
152
|
+
]) !== null;
|
|
153
|
+
}
|
|
154
|
+
const REMOTE_URL_RE = /^(?:https?:\/\/(?:[^/@]+@)?[^/]+\/|ssh:\/\/(?:[^/@]+@)?[^/]+\/|(?:[^/@:]+@)?[^/:]+:)([^/]+)\/([^/]+?)(?:\.git)?\/?$/i;
|
|
155
|
+
/**
|
|
156
|
+
* "owner/name", lowercased, parsed out of a git remote URL, or null when it doesn't match: https, `ssh://`, or
|
|
157
|
+
* scp-like (`[user@]host:owner/name`, which also covers an `~/.ssh/config` host alias in place of `user@host`).
|
|
158
|
+
*/
|
|
159
|
+
function parseRemoteRepo(url) {
|
|
160
|
+
const [, owner, name] = REMOTE_URL_RE.exec(url.trim()) ?? [];
|
|
161
|
+
return owner && name ? `${owner.toLowerCase()}/${name.toLowerCase()}` : null;
|
|
162
|
+
}
|
|
163
|
+
function localRemoteRepos(cwd) {
|
|
164
|
+
const out = getExecutor().runFileQuiet("git", [
|
|
165
|
+
"-C",
|
|
166
|
+
cwd,
|
|
167
|
+
"remote",
|
|
168
|
+
"-v"
|
|
169
|
+
]);
|
|
170
|
+
const repos = /* @__PURE__ */ new Set();
|
|
171
|
+
for (const line of out ? out.split("\n") : []) {
|
|
172
|
+
const url = /^\S+\s+(\S+)\s+\((?:fetch|push)\)$/.exec(line)?.[1];
|
|
173
|
+
const repo = url ? parseRemoteRepo(url) : null;
|
|
174
|
+
if (repo) repos.add(repo);
|
|
175
|
+
}
|
|
176
|
+
return repos;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Asks GitHub, through `gh`, which pull requests have `branch` as their head, run from `cwd` so `gh` picks the
|
|
180
|
+
* repository from its remotes. Each call is one fixed `gh pr list` invocation. Once `gh` is missing, signed out or
|
|
181
|
+
* times out, every later lookup through the same function answers `unavailable` without running it again.
|
|
182
|
+
*/
|
|
183
|
+
function pullRequestLookup() {
|
|
184
|
+
let unavailable;
|
|
185
|
+
return (cwd, branch, head) => {
|
|
186
|
+
const exec = getExecutor();
|
|
187
|
+
if (unavailable === void 0) unavailable = exec.findExecutable("gh") ? null : "gh is not installed";
|
|
188
|
+
if (unavailable) return { unavailable };
|
|
189
|
+
let out;
|
|
190
|
+
try {
|
|
191
|
+
out = exec.runFile("gh", [
|
|
192
|
+
"pr",
|
|
193
|
+
"list",
|
|
194
|
+
"--head",
|
|
195
|
+
branch,
|
|
196
|
+
"--state",
|
|
197
|
+
"all",
|
|
198
|
+
"--limit",
|
|
199
|
+
"20",
|
|
200
|
+
"--json",
|
|
201
|
+
GH_FIELDS
|
|
202
|
+
], {
|
|
203
|
+
cwd,
|
|
204
|
+
timeoutMs: GH_TIMEOUT_MS,
|
|
205
|
+
env: GH_ENV
|
|
206
|
+
});
|
|
207
|
+
} catch (error) {
|
|
208
|
+
const failure = ghFailure(error, "gh pr list");
|
|
209
|
+
if (failure.sticky) unavailable = failure.unavailable;
|
|
210
|
+
return { unavailable: failure.unavailable };
|
|
211
|
+
}
|
|
212
|
+
let pulls;
|
|
213
|
+
try {
|
|
214
|
+
pulls = JSON.parse(out);
|
|
215
|
+
} catch {
|
|
216
|
+
return { unavailable: "gh pr list printed no JSON" };
|
|
217
|
+
}
|
|
218
|
+
return { pullRequest: Array.isArray(pulls) ? selectPullRequest(pulls, head, ancestry(cwd), localRemoteRepos(cwd)) : null };
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
function branchesQuery(count, detail) {
|
|
222
|
+
const variables = Array.from({ length: count }, (_, i) => `, $b${i}: String!`).join("");
|
|
223
|
+
const nodes = `${GH_SCALAR_FIELDS.replaceAll(",", " ")} ${GH_GRAPHQL_REPO_SELECTION}` + (detail ? ` ${GH_DETAIL_FIELDS}` : "");
|
|
224
|
+
return `query($owner: String!, $repo: String!${variables}) { repository(owner: $owner, name: $repo) {${Array.from({ length: count }, (_, i) => ` b${i}: pullRequests(headRefName: $b${i}, states: [OPEN, CLOSED, MERGED], first: 20, orderBy: {field: CREATED_AT, direction: DESC}) { nodes { ${nodes} } }`).join("")} } }`;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* {@link pullRequestLookup} for every branch of one repository in one fixed `gh api graphql` call run from `repo`,
|
|
228
|
+
* which asks for the same 20 newest pull requests of each head branch that `gh pr list --head` returns. `gh` fills
|
|
229
|
+
* `{owner}` and `{repo}` from the remotes of `repo`; branch names travel as variables. Once `gh` is missing, signed
|
|
230
|
+
* out or times out, every later call through the same function answers `unavailable` without running it again.
|
|
231
|
+
* With `detail`, it also asks for each pull request's title, review decision and head commit check counts.
|
|
232
|
+
*/
|
|
233
|
+
function pullRequestLookups({ detail = false } = {}) {
|
|
234
|
+
let unavailable;
|
|
235
|
+
return async (repo, queries) => {
|
|
236
|
+
const exec = getExecutor();
|
|
237
|
+
if (unavailable === void 0) unavailable = exec.findExecutable("gh") ? null : "gh is not installed";
|
|
238
|
+
const all = (lookup) => queries.map(() => lookup);
|
|
239
|
+
if (unavailable) return all({ unavailable });
|
|
240
|
+
if (!queries.length) return [];
|
|
241
|
+
const args = [
|
|
242
|
+
"api",
|
|
243
|
+
"graphql",
|
|
244
|
+
"-F",
|
|
245
|
+
"owner={owner}",
|
|
246
|
+
"-F",
|
|
247
|
+
"repo={repo}"
|
|
248
|
+
];
|
|
249
|
+
queries.forEach(({ branch }, i) => args.push("-f", `b${i}=${branch}`));
|
|
250
|
+
args.push("-f", `query=${branchesQuery(queries.length, detail)}`);
|
|
251
|
+
let out;
|
|
252
|
+
try {
|
|
253
|
+
out = await exec.runFileAsync("gh", args, {
|
|
254
|
+
cwd: repo,
|
|
255
|
+
timeoutMs: GH_TIMEOUT_MS,
|
|
256
|
+
env: GH_ENV
|
|
257
|
+
});
|
|
258
|
+
} catch (error) {
|
|
259
|
+
const failure = ghFailure(error, "gh api graphql");
|
|
260
|
+
if (failure.sticky) unavailable = failure.unavailable;
|
|
261
|
+
return all({ unavailable: failure.unavailable });
|
|
262
|
+
}
|
|
263
|
+
let found;
|
|
264
|
+
try {
|
|
265
|
+
found = JSON.parse(out).data?.repository;
|
|
266
|
+
} catch {
|
|
267
|
+
return all({ unavailable: "gh api graphql printed no JSON" });
|
|
268
|
+
}
|
|
269
|
+
if (!found) return all({ unavailable: "gh api graphql printed no repository" });
|
|
270
|
+
const ownRepos = localRemoteRepos(repo);
|
|
271
|
+
return queries.map(({ cwd, head }, i) => {
|
|
272
|
+
const pulls = found[`b${i}`]?.nodes;
|
|
273
|
+
return { pullRequest: Array.isArray(pulls) ? selectPullRequest(pulls, head, ancestry(cwd), ownRepos) : null };
|
|
274
|
+
});
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
/** The merged or closed pull request whose commits include HEAD, which makes the worktree removable. */
|
|
278
|
+
function endedPullRequest(lookup) {
|
|
279
|
+
const pr = lookup && "pullRequest" in lookup ? lookup.pullRequest : null;
|
|
280
|
+
return pr && pr.state !== "open" && pr.containsHead ? pr : null;
|
|
281
|
+
}
|
|
282
|
+
/** "PR #123 merged", for reports. */
|
|
283
|
+
function describePullRequest(pr) {
|
|
284
|
+
return `PR #${pr.number} ${pr.state}`;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Looks up the pull request of each worktree's branch and HEAD, with one {@link pullRequestLookups} call per
|
|
288
|
+
* repository. The map holds null for a worktree without one, and leaves out a worktree whose HEAD git cannot read
|
|
289
|
+
* or whose lookup was unavailable.
|
|
290
|
+
*/
|
|
291
|
+
function worktreePullRequests() {
|
|
292
|
+
const lookup = pullRequestLookups();
|
|
293
|
+
return async (worktrees) => {
|
|
294
|
+
const exec = getExecutor();
|
|
295
|
+
const repos = /* @__PURE__ */ new Map();
|
|
296
|
+
for (const { path, branch, repository } of worktrees) {
|
|
297
|
+
let head;
|
|
298
|
+
try {
|
|
299
|
+
head = (await exec.runFileAsync("git", [
|
|
300
|
+
"-C",
|
|
301
|
+
path,
|
|
302
|
+
"rev-parse",
|
|
303
|
+
"HEAD"
|
|
304
|
+
], { timeoutMs: 5e3 })).trim();
|
|
305
|
+
} catch {
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
repos.set(repository, [...repos.get(repository) ?? [], {
|
|
309
|
+
cwd: path,
|
|
310
|
+
branch,
|
|
311
|
+
head
|
|
312
|
+
}]);
|
|
313
|
+
}
|
|
314
|
+
const found = /* @__PURE__ */ new Map();
|
|
315
|
+
for (const [repo, queries] of repos) (await lookup(repo, queries)).forEach((result, i) => {
|
|
316
|
+
if ("pullRequest" in result) found.set(queries[i].cwd, result.pullRequest);
|
|
317
|
+
});
|
|
318
|
+
return found;
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
//#endregion
|
|
322
|
+
export { pullRequestLookup as a, worktreePullRequests as c, parseRemoteRepo as i, describePullRequest as n, pullRequestLookups as o, endedPullRequest as r, selectPullRequest as s, checkCounts as t };
|