forge-memory 0.2.116 → 0.2.118
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/bin/forge-memory.mjs +105 -19
- package/package.json +1 -1
package/bin/forge-memory.mjs
CHANGED
|
@@ -1969,7 +1969,16 @@ async function createPairing(config, options = {}) {
|
|
|
1969
1969
|
cookie: operatorCookie,
|
|
1970
1970
|
...(publicUrl ? { referer: publicUrl } : {})
|
|
1971
1971
|
},
|
|
1972
|
-
body: JSON.stringify({
|
|
1972
|
+
body: JSON.stringify({
|
|
1973
|
+
userId: null,
|
|
1974
|
+
transportMode,
|
|
1975
|
+
fallbackMode: publicUrl
|
|
1976
|
+
? publicUrl.includes(".ts.net")
|
|
1977
|
+
? "tailscale"
|
|
1978
|
+
: "fixed-ip"
|
|
1979
|
+
: "none",
|
|
1980
|
+
publicUrl: publicUrl ?? undefined
|
|
1981
|
+
})
|
|
1973
1982
|
});
|
|
1974
1983
|
} catch (error) {
|
|
1975
1984
|
const healthResult = await health(config, 1_500);
|
|
@@ -2007,6 +2016,65 @@ async function createPairing(config, options = {}) {
|
|
|
2007
2016
|
return pairing;
|
|
2008
2017
|
}
|
|
2009
2018
|
|
|
2019
|
+
async function resolveIosPairingOptions(parsed) {
|
|
2020
|
+
if (parsed.flags.manualHttp) {
|
|
2021
|
+
return {
|
|
2022
|
+
transportMode: "manual-http",
|
|
2023
|
+
publicUrl: validatePairingOptions({
|
|
2024
|
+
transportMode: "manual-http",
|
|
2025
|
+
publicUrl: parsed.values.publicUrl
|
|
2026
|
+
})
|
|
2027
|
+
};
|
|
2028
|
+
}
|
|
2029
|
+
if (parsed.flags.yes || parsed.flags.json || !process.stdin.isTTY || parsed.values.publicUrl) {
|
|
2030
|
+
return {
|
|
2031
|
+
transportMode: "iroh",
|
|
2032
|
+
publicUrl: validatePairingOptions({
|
|
2033
|
+
transportMode: "iroh",
|
|
2034
|
+
publicUrl: parsed.values.publicUrl
|
|
2035
|
+
})
|
|
2036
|
+
};
|
|
2037
|
+
}
|
|
2038
|
+
console.log(color.bold("iOS companion connection"));
|
|
2039
|
+
console.log(color.dim("Default: Iroh tunnel. You can choose Tailscale or a fixed/private IP as the direct phone path."));
|
|
2040
|
+
const choice = (
|
|
2041
|
+
await promptLine("Connection [iroh/tailscale/ip]", "iroh")
|
|
2042
|
+
).toLowerCase();
|
|
2043
|
+
if (choice === "tailscale" || choice === "ts") {
|
|
2044
|
+
const publicUrl = await promptLine(
|
|
2045
|
+
"Tailscale Forge URL",
|
|
2046
|
+
parsed.values.publicUrl ?? "https://your-mac.tailnet.ts.net/forge/"
|
|
2047
|
+
);
|
|
2048
|
+
return {
|
|
2049
|
+
transportMode: "manual-http",
|
|
2050
|
+
publicUrl: validatePairingOptions({
|
|
2051
|
+
transportMode: "manual-http",
|
|
2052
|
+
publicUrl
|
|
2053
|
+
})
|
|
2054
|
+
};
|
|
2055
|
+
}
|
|
2056
|
+
if (choice === "ip" || choice === "fixed" || choice === "private") {
|
|
2057
|
+
const publicUrl = await promptLine(
|
|
2058
|
+
"Private/fixed Forge URL",
|
|
2059
|
+
parsed.values.publicUrl ?? "http://192.168.1.98:4317/forge/"
|
|
2060
|
+
);
|
|
2061
|
+
return {
|
|
2062
|
+
transportMode: "manual-http",
|
|
2063
|
+
publicUrl: validatePairingOptions({
|
|
2064
|
+
transportMode: "manual-http",
|
|
2065
|
+
publicUrl
|
|
2066
|
+
})
|
|
2067
|
+
};
|
|
2068
|
+
}
|
|
2069
|
+
return {
|
|
2070
|
+
transportMode: "iroh",
|
|
2071
|
+
publicUrl: validatePairingOptions({
|
|
2072
|
+
transportMode: "iroh",
|
|
2073
|
+
publicUrl: parsed.values.publicUrl
|
|
2074
|
+
})
|
|
2075
|
+
};
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2010
2078
|
function assertPairingTransportUsable(pairing, { requestedTransportMode }) {
|
|
2011
2079
|
const payload = pairing?.qrPayload;
|
|
2012
2080
|
if (!payload || requestedTransportMode !== "iroh") {
|
|
@@ -2015,6 +2083,23 @@ function assertPairingTransportUsable(pairing, { requestedTransportMode }) {
|
|
|
2015
2083
|
const resolvedTransportMode = payload.transportMode ?? payload.transport?.protocol;
|
|
2016
2084
|
const resolvedProtocol = payload.transport?.protocol;
|
|
2017
2085
|
if (resolvedTransportMode === "iroh" || resolvedProtocol === "iroh") {
|
|
2086
|
+
const phoneFacingUrls = [
|
|
2087
|
+
payload.apiBaseUrl,
|
|
2088
|
+
payload.uiBaseUrl,
|
|
2089
|
+
payload.transport?.publicBaseUrl
|
|
2090
|
+
].filter(Boolean);
|
|
2091
|
+
const loopbackUrl = phoneFacingUrls.find((url) => isLoopbackPairingUrl(url));
|
|
2092
|
+
if (loopbackUrl) {
|
|
2093
|
+
throw new PairingTransportUnavailableError(
|
|
2094
|
+
[
|
|
2095
|
+
"Forge created an Iroh pairing that exposes a loopback URL as phone-facing pairing data.",
|
|
2096
|
+
`Bad URL: ${loopbackUrl}.`,
|
|
2097
|
+
"A physical iPhone cannot reach localhost on this Mac.",
|
|
2098
|
+
"Use Iroh logical URLs, a selected Tailscale URL, or a selected private/fixed IP URL."
|
|
2099
|
+
].join(" "),
|
|
2100
|
+
{ apiBaseUrl: payload.apiBaseUrl, transportMode: resolvedTransportMode, protocol: resolvedProtocol }
|
|
2101
|
+
);
|
|
2102
|
+
}
|
|
2018
2103
|
return;
|
|
2019
2104
|
}
|
|
2020
2105
|
const apiBaseUrl = payload.apiBaseUrl ?? "";
|
|
@@ -2039,6 +2124,15 @@ function assertPairingTransportUsable(pairing, { requestedTransportMode }) {
|
|
|
2039
2124
|
|
|
2040
2125
|
function validatePairingOptions({ transportMode, publicUrl }) {
|
|
2041
2126
|
const normalizedPublicUrl = normalizePublicPairingUrl(publicUrl);
|
|
2127
|
+
if (normalizedPublicUrl && isLoopbackPairingUrl(normalizedPublicUrl)) {
|
|
2128
|
+
throw new Error(
|
|
2129
|
+
[
|
|
2130
|
+
`--public-url points at ${normalizedPublicUrl}, which is loopback-only.`,
|
|
2131
|
+
"A physical iPhone cannot reach localhost on this Mac.",
|
|
2132
|
+
"Use Iroh, Tailscale, or a private/fixed IP URL."
|
|
2133
|
+
].join(" ")
|
|
2134
|
+
);
|
|
2135
|
+
}
|
|
2042
2136
|
if (transportMode !== "manual-http") {
|
|
2043
2137
|
return normalizedPublicUrl;
|
|
2044
2138
|
}
|
|
@@ -2052,15 +2146,6 @@ function validatePairingOptions({ transportMode, publicUrl }) {
|
|
|
2052
2146
|
].join(" ")
|
|
2053
2147
|
);
|
|
2054
2148
|
}
|
|
2055
|
-
if (isLoopbackPairingUrl(normalizedPublicUrl)) {
|
|
2056
|
-
throw new Error(
|
|
2057
|
-
[
|
|
2058
|
-
`Manual HTTP --public-url points at ${normalizedPublicUrl}, which is loopback-only.`,
|
|
2059
|
-
"A physical iPhone cannot reach localhost on this Mac.",
|
|
2060
|
-
"Use a Tailscale or LAN URL, or omit --manual-http and use Iroh pairing."
|
|
2061
|
-
].join(" ")
|
|
2062
|
-
);
|
|
2063
|
-
}
|
|
2064
2149
|
return normalizedPublicUrl;
|
|
2065
2150
|
}
|
|
2066
2151
|
|
|
@@ -2290,10 +2375,13 @@ async function runInstall(parsed, command) {
|
|
|
2290
2375
|
(parsed.flags.yes
|
|
2291
2376
|
? true
|
|
2292
2377
|
: await promptYesNo("Pair the iOS companion now?", true)));
|
|
2378
|
+
const pairingOptions = shouldPair
|
|
2379
|
+
? await resolveIosPairingOptions(parsed)
|
|
2380
|
+
: null;
|
|
2293
2381
|
let irohTransportResult = null;
|
|
2294
2382
|
if (
|
|
2295
2383
|
shouldPair &&
|
|
2296
|
-
|
|
2384
|
+
pairingOptions?.transportMode !== "manual-http" &&
|
|
2297
2385
|
!parsed.flags.dryRun
|
|
2298
2386
|
) {
|
|
2299
2387
|
irohTransportResult = await withProgress(
|
|
@@ -2357,8 +2445,8 @@ async function runInstall(parsed, command) {
|
|
|
2357
2445
|
parsed.flags,
|
|
2358
2446
|
() =>
|
|
2359
2447
|
createPairing(config, {
|
|
2360
|
-
transportMode:
|
|
2361
|
-
publicUrl:
|
|
2448
|
+
transportMode: pairingOptions.transportMode,
|
|
2449
|
+
publicUrl: pairingOptions.publicUrl
|
|
2362
2450
|
})
|
|
2363
2451
|
);
|
|
2364
2452
|
if (pairing?.qrPayload && !parsed.flags.json) {
|
|
@@ -2584,11 +2672,9 @@ async function runUi(parsed) {
|
|
|
2584
2672
|
|
|
2585
2673
|
async function runPairIos(parsed) {
|
|
2586
2674
|
const config = await readConfig();
|
|
2587
|
-
const
|
|
2588
|
-
const
|
|
2589
|
-
|
|
2590
|
-
publicUrl: parsed.values.publicUrl
|
|
2591
|
-
});
|
|
2675
|
+
const pairingOptions = await resolveIosPairingOptions(parsed);
|
|
2676
|
+
const transportMode = pairingOptions.transportMode;
|
|
2677
|
+
const publicUrl = pairingOptions.publicUrl;
|
|
2592
2678
|
if (transportMode === "iroh") {
|
|
2593
2679
|
await withProgress(
|
|
2594
2680
|
"Preparing Forge Companion Iroh transport",
|
|
@@ -2952,7 +3038,7 @@ Options:
|
|
|
2952
3038
|
--skip-adapters Configure UI/runtime only
|
|
2953
3039
|
--skip-pair-ios Do not prompt or create iOS pairing
|
|
2954
3040
|
--manual-http Use direct HTTP/TCP for iOS pairing instead of the default Iroh transport
|
|
2955
|
-
--public-url <url> Phone-
|
|
3041
|
+
--public-url <url> Phone-facing Tailscale/LAN/fixed URL for direct pairing or Iroh fallback; never localhost
|
|
2956
3042
|
--no-start Configure without starting runtime
|
|
2957
3043
|
--no-doctor Skip install-time doctor checks
|
|
2958
3044
|
--repair Let doctor create missing folders and restart unhealthy runtime
|
package/package.json
CHANGED